自定义生成Customize your build

使用标准生成进程(导入 Microsoft.Common.props 和 Microsoft.Common.targets)的 MSBuild 项目有多个可用于自定义生成过程的扩展性挂钩 。MSBuild projects that use the standard build process (importing Microsoft.Common.props and Microsoft.Common.targets) have several extensibility hooks that you can use to customize your build process.

向项目的命令行 MSBuild 调用添加参数Add arguments to command-line MSBuild invocations for your project

源目录中或之上的 Directory.Build.rsp 文件将应用到项目的命令行生成。A Directory.Build.rsp file in or above your source directory will be applied to command-line builds of your project. 有关详细信息,请参阅 MSBuild 响应文件For details, see MSBuild response files.

Directory.Build.props 和 Directory.Build.targetsDirectory.Build.props and Directory.Build.targets

在 MSBuild 15 版之前,如果要向解决方案中的项目提供新的自定义属性,必须手动向解决方案中的每个项目文件添加一个针对该属性的引用。Prior to MSBuild version 15, if you wanted to provide a new, custom property to projects in your solution, you had to manually add a reference to that property to every project file in the solution. 另外,还必须在 .props 文件中定义属性,然后在解决方案的每个项目中显式导入该 .props 文件。Or, you had to define the property in a .props file and then explicitly import the .props file in every project in the solution, among other things.

但现在,通过在包含源的根文件夹的名为 Directory.Build.props 的单个文件中定义一个新属性,只需一步即可向每个项目添加该属性。However, now you can add a new property to every project in one step by defining it in a single file called Directory.Build.props in the root folder that contains your source. 在 MSBuild 运行时,Microsoft.Common.props 会搜索 Directory.Build.props 文件的目录结构(Microsoft.Common.targets 将查找 Directory.Build.targets)。When MSBuild runs, Microsoft.Common.props searches your directory structure for the Directory.Build.props file (and Microsoft.Common.targets looks for Directory.Build.targets). 如果找到,就会导入该属性。If it finds one, it imports the property. Directory.Build.props 是用户定义文件,对目录下的项目提供自定义选项。Directory.Build.props is a user-defined file that provides customizations to projects under a directory.

备注

基于 Linux 的文件系统区分大小写。Linux-based file systems are case-sensitive. 请确保 Directory.Build.props 文件名的大小写完全匹配,否则将不会在生成流程中检测到它。Make sure the casing of the Directory.Build.props filename matches exactly, or it won't be detected during the build process.

有关详细信息,请参阅此 GitHub 问题See this GitHub issue for more information.

Directory.Build.props 示例Directory.Build.props example

例如,如果想要使所有项目都可以访问新的 Roslyn /deterministic 功能(属性 $(Deterministic) 在 Roslyn CoreCompile 目标中公开了此功能),可以执行以下操作。For example, if you wanted to enable all of your projects to access the new Roslyn /deterministic feature (which is exposed in the Roslyn CoreCompile target by the property $(Deterministic)), you could do the following.

  1. 在存储库根目录中创建一个名为 Directory.Build.props 的新文件。Create a new file in the root of your repo called Directory.Build.props.

  2. 将以下 XML 添加到此文件。Add the following XML to the file.

    <Project>
     <PropertyGroup>
       <Deterministic>true</Deterministic>
     </PropertyGroup>
    </Project>
    
  3. 运行 MSBuild。Run MSBuild. 项目现有的 Microsoft.Common.props 和 Microsoft.Common.targets 导入会找到该文件并将其导入。Your project’s existing imports of Microsoft.Common.props and Microsoft.Common.targets find the file and import it.

搜索范围Search scope

搜索 Directory.Build.props 文件时,MSBuild 将从项目位置 ($(MSBuildProjectFullPath)) 向上搜索目录结构,找到 Directory.Build.props 文件后停止。When searching for a Directory.Build.props file, MSBuild walks the directory structure upwards from your project location ($(MSBuildProjectFullPath)), stopping after it locates a Directory.Build.props file. 例如,如果 $(MSBuildProjectFullPath) 为 c:\users\username\code\test\case1,MSBuild 将从该位置开始搜索,然后向上搜索目录结构,直到找到 Directory.Build.props 文件,如以下目录结构中所示。For example, if your $(MSBuildProjectFullPath) was c:\users\username\code\test\case1, MSBuild would start searching there and then search the directory structure upward until it located a Directory.Build.props file, as in the following directory structure.

c:\users\username\code\test\case1
c:\users\username\code\test
c:\users\username\code
c:\users\username
c:\users
c:\

解决方案文件的位置与 Directory.Build.props 无关。The location of the solution file is irrelevant to Directory.Build.props.

导入顺序Import order

Directory.Build.props 很早便已导入 Microsoft.Common.props,因此它无法使用后来定义的属性 。Directory.Build.props is imported very early in Microsoft.Common.props, and properties defined later are unavailable to it. 因此,请避免引用尚未定义的属性(否则计算结果将为空)。So, avoid referring to properties that are not yet defined (and will evaluate to empty).

Directory.Build.props 中设置的属性可能会在项目文件或导入文件中的其他位置被覆盖,因此,应考虑将 Directory.Build.props 中的设置指定为项目的默认值 。Properties that are set in Directory.Build.props can be overridden elsewhere in the project file or in imported files, so you should think of the settings in Directory.Build.props as specifying the defaults for your projects.

从 NuGet 包导入 .targets 文件后,会从 Microsoft.Common.targets 导入 Directory.Build.targets。Directory.Build.targets is imported from Microsoft.Common.targets after importing .targets files from NuGet packages. 因此,它可以覆盖大多数生成逻辑中定义的属性和目标,或者为所有项目设置属性,而不考虑各个项目的设置。So, it can override properties and targets defined in most of the build logic, or set properties for all your projects regardless of what the individual projects set.

如果需要为单个项目设置覆盖先前所有设置的属性和目标,请在最终导入后将该逻辑放在项目文件中。When you need to set a property or define a target for an individual project that overrides any prior settings, put that logic in the project file after the final import. 要在 SDK 样式的项目中执行此操作,必须先将 SDK 样式的属性替换为等效的导入项。In order to do this in an SDK-style project, you first have to replace the SDK-style attribute with the equivalent imports. 查看如何使用 MSBuild 项目 SDKSee How to use MSBuild project SDKs.

备注

MSBuild 引擎在评估期间读取所有导入文件,然后才开始对任何项目(包括任何 PreBuildEvent)执行生成操作,以此确保 PreBuildEvent 或生成过程的任何其他部分都不会修改这些文件。The MSBuild engine reads in all imported files during evaluation, before starting build execution for any project (including any PreBuildEvent), so these files are not expected to be modified by the PreBuildEvent or any other part of the build process. 在下次调用 Msbuild.exe 或 Visual Studio 下次生成之后,修改才会生效。Any modifications do not take effect until the next invocation of MSBuild.exe or the next Visual Studio build.

用例:多级别合并Use case: multi-level merging

假设你具有此标准解决方案结构:Suppose you have this standard solution structure:

\
  MySolution.sln
  Directory.Build.props     (1)
  \src
    Directory.Build.props   (2-src)
    \Project1
    \Project2
  \test
    Directory.Build.props   (2-test)
    \Project1Tests
    \Project2Tests

则可能需要具有所有项目 (1) 的通用属性、src 项目 (2-src) 的通用属性,以及 test 项目 (2-test) 的通用属性。It might be desirable to have common properties for all projects (1), common properties for src projects (2-src), and common properties for test projects (2-test).

若要 MSBuild 正确地合并“内部”文件(2-src 和 2-test)和“外部”文件 (1),必须考虑到 MSBuild 找到 Directory.Build.props 文件后会立即停止进一步的扫描 。To make MSBuild correctly merge the "inner" files (2-src and 2-test) with the "outer" file (1), you must take into account that once MSBuild finds a Directory.Build.props file, it stops further scanning. 要继续扫描并合并到外部文件,请将此代码置于这两个内部文件中:To continue scanning and merge into the outer file, place this code into both inner files:

<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />

MSBuild 的常规方法汇总如下:A summary of MSBuild's general approach is as follows:

  • 对于任何给定的项目,MSBuild 在解决方案结构中向上查找第一个 Directory.Build.props,将其与默认项合并,然后停止扫描For any given project, MSBuild finds the first Directory.Build.props upward in the solution structure, merges it with defaults, and stops scanning for more
  • 如果要找到并合并多个级别,则从“内部”文件 <Import...>(如上所示)“外部”文件If you want multiple levels to be found and merged, then <Import...> (shown above) the "outer" file from the "inner" file
  • 如果“外部”文件本身不会再导入其上的内容,则扫描在此处停止If the "outer" file does not itself also import something above it, then scanning stops there
  • 要控制扫描/合并过程,请使用 $(DirectoryBuildPropsPath)$(ImportDirectoryBuildProps)To control the scanning/merging process, use $(DirectoryBuildPropsPath) and $(ImportDirectoryBuildProps)

或再简单点:不能导入任何内容的第一个 Directory.Build.props 即为 MSBuild 停止的位置。Or more simply: the first Directory.Build.props that doesn't import anything is where MSBuild stops.

选择将属性添加到 .props 文件或 .targets 文件Choose between adding properties to a .props or .targets file

MSBuild 依赖于导入顺序,属性(或 UsingTask 或目标)的最后一个定义是使用的定义。MSBuild is import-order dependent, and the last definition of a property (or a UsingTask or target) is the definition used.

使用显式导入时,可以随时从 .props 或 .targets 文件导入。When using explicit imports, you can import from a .props or .targets file at any point. 下面介绍广泛使用的约定:Here is the widely used convention:

  • .props 文件在导入顺序的早期导入。.props files are imported early in the import order.

  • .targets 文件在生成顺序的后期导入。.targets files are imported late in the build order.

此约定由 <Project Sdk="SdkName"> 导入强制执行(即,在文件的所有内容之前首先导入 Sdk.props,然后在文件的所有内容之后最后导入 Sdk.targets)。This convention is enforced by <Project Sdk="SdkName"> imports (that is, the import of Sdk.props comes first, before all of the contents of the file, then Sdk.targets comes last, after all of the contents of the file).

在决定在何处放置属性后,使用以下通用原则:When deciding where to put the properties, use the following general guidelines:

  • 对于许多属性,在何处定义它们并不重要,因为它们不会被覆盖,只能在执行时读取。For many properties, it doesn't matter where they're defined, because they're not overwritten and will be read only at execution time.

  • 对于可能在单个项目中自定义的行为,请在 .props 文件中设置默认值。For behavior that might be customized in an individual project, set defaults in .props files.

  • 通过读取可能自定义属性的值,避免在 .props 文件中设置依赖属性,因为在 MSBuild 读取用户项目之前不会进行自定义。Avoid setting dependent properties in .props files by reading the value of a possibly customized property, because the customization won't happen until MSBuild reads the user's project.

  • 在 .targets 文件中设置依赖属性,因为它们将从单个项目中提取自定义项。Set dependent properties in .targets files, because they'll pick up customizations from individual projects.

  • 如果需要覆盖属性,请在所有用户项目自定义项生效后,在 .targets 文件中执行此操作。If you need to override properties, do it in a .targets file, after all user-project customizations have had a chance to take effect. 使用派生属性时务必小心;还可能需要覆盖派生属性。Be cautious when using derived properties; derived properties may need to be overridden as well.

  • 包括 .props 文件中的项目(以属性为条件)。Include items in .props files (conditioned on a property). 在任何项目之前都要考虑所有属性,因此可以提取用户项目属性自定义项,这使用户的项目有机会 RemoveUpdate 导入所引入的任何项目。All properties are considered before any item, so user-project property customizations get picked up, and this gives the user's project the opportunity to Remove or Update any item brought in by the import.

  • 定义 .targets 文件中的目标。Define targets in .targets files. 但是,如果 SDK 导入了 .targets 文件,请记住此方案使得覆盖目标更加困难,因为默认情况下用户的项目没有可以覆盖它的地方。However, if the .targets file is imported by an SDK, remember that this scenario makes overriding the target more difficult because the user's project doesn't have a place to override it by default.

  • 如果可能,宁可在评估时自定义属性,也不更改目标内的属性。If possible, prefer customizing properties at evaluation time over changing properties inside a target. 此原则可以更轻松地加载项目并了解正在执行的操作。This guideline makes it easier to load a project and understand what it's doing.

MSBuildProjectExtensionsPathMSBuildProjectExtensionsPath

默认情况下,Microsoft.Common.props 导入 $(MSBuildProjectExtensionsPath)$(MSBuildProjectFile).*.props,Microsoft.Common.targets 导入 $(MSBuildProjectExtensionsPath)$(MSBuildProjectFile).*.targetsBy default, Microsoft.Common.props imports $(MSBuildProjectExtensionsPath)$(MSBuildProjectFile).*.props and Microsoft.Common.targets imports $(MSBuildProjectExtensionsPath)$(MSBuildProjectFile).*.targets. MSBuildProjectExtensionsPath 的默认值是 $(BaseIntermediateOutputPath)obj/The default value of MSBuildProjectExtensionsPath is $(BaseIntermediateOutputPath), obj/. NuGet 用此机制来引用随包提供的生成逻辑,也就是说,在还原时,它会创建引用包内容的 {project}.nuget.g.props 文件。NuGet uses this mechanism to refer to build logic delivered with packages; that is, at restore time, it creates {project}.nuget.g.props files that refer to the package contents.

可以通过在 Directory.Build.props 中或者在导入 Microsoft.Common.props 前将属性 ImportProjectExtensionProps 设为 false 来禁用此扩展性机制 。You can disable this extensibility mechanism by setting the property ImportProjectExtensionProps to false in a Directory.Build.props or before importing Microsoft.Common.props.

备注

禁用 MSBuildProjectExtensionsPath 导入将阻止在 NuGet 包中提供的生成逻辑应用到你的项目。Disabling MSBuildProjectExtensionsPath imports will prevent build logic delivered in NuGet packages from applying to your project. 一些 NuGet 包需要生成逻辑来执行其功能,并且在禁用该功能时会呈现不可用。Some NuGet packages require build logic to perform their function and will be rendered useless when this is disabled.

.user 文件.user file

Microsoft.Common.CurrentVersion.targets 会导入 $(MSBuildProjectFullPath).user(如果存在),因此可以使用其他文件扩展名在你的项目旁创建一个文件。Microsoft.Common.CurrentVersion.targets imports $(MSBuildProjectFullPath).user if it exists, so you can create a file next to your project with that additional extension. 对于计划签入源代码管理的长期更改,最好更改项目本身,以便将来的维护人员不必了解此扩展机制。For long-term changes you plan to check into source control, prefer changing the project itself, so that future maintainers do not have to know about this extension mechanism.

MSBuildExtensionsPath 和 MSBuildUserExtensionsPathMSBuildExtensionsPath and MSBuildUserExtensionsPath

警告

如果使用这些扩展机制,则较难获取计算机上的可重复生成。Using these extension mechanisms makes it harder to get repeatable builds across machines. 尝试使用可以签入源代码管理系统并在基本代码的所有开发人员之间共享的配置。Try to use a configuration that can be checked into your source control system and shared among all developers of your codebase.

按照惯例,许多核心生成逻辑文件By convention, many core build logic files import

$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\{TargetFileName}\ImportBefore\*.targets

会在其内容前后各导入一次before their contents, and

$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\{TargetFileName}\ImportAfter\*.targets

afterward. 这一约定使已安装的 SDK 可以增强常见项目类型的生成逻辑。This convention allows installed SDKs to augment the build logic of common project types.

$(MSBuildUserExtensionsPath) 中搜索相同的目录结构,即按用户文件夹 %LOCALAPPDATA%\Microsoft\MSBuild。The same directory structure is searched in $(MSBuildUserExtensionsPath), which is the per-user folder %LOCALAPPDATA%\Microsoft\MSBuild. 放置在该文件夹中的文件将被导入该用户凭据下运行的相应项目类型的所有生成。Files placed in that folder will be imported for all builds of the corresponding project type run under that user's credentials. 通过在模式 ImportUserLocationsByWildcardBefore{ImportingFileNameWithNoDots} 中设置以导入文件命名的属性,可以禁用用户扩展。You can disable the user extensions by setting properties named after the importing file in the pattern ImportUserLocationsByWildcardBefore{ImportingFileNameWithNoDots}. 例如,将 ImportUserLocationsByWildcardBeforeMicrosoftCommonProps 设置为 false 会阻止导入 $(MSBuildUserExtensionsPath)\$(MSBuildToolsVersion)\Imports\Microsoft.Common.props\ImportBefore\*For example, setting ImportUserLocationsByWildcardBeforeMicrosoftCommonProps to false would prevent importing $(MSBuildUserExtensionsPath)\$(MSBuildToolsVersion)\Imports\Microsoft.Common.props\ImportBefore\*.

自定义解决方案生成Customize the solution build

重要

以这种方式自定义解决方案生成将仅适用于带有 MSBuild.exe 的命令行生成。Customizing the solution build in this way applies only to command-line builds with MSBuild.exe. 它不适用于 Visual Studio 中的生成。It does not apply to builds inside Visual Studio. 出于此原因,不建议将自定义项置于解决方案级别。For this reason, it is not recommended to put customization at the solution level. 自定义一个解决方案中所有项目的更好方法是在解决方案文件夹中使用 Directory.Build.props 和 Directory.build.targets 文件,如本文其他部分所述。A better alternative for customizing all projects in a solution is to use Directory.Build.props and Directory.build.targets files in the solution folder, as discussed elsewhere in this article.

当 MSBuild 生成解决方案文件时,它首先在内部转换为项目文件,然后再生成它。When MSBuild builds a solution file, it first translates it internally into a project file and then builds that. 已生成的项目文件在定义任何目标前导入 before.{solutionname}.sln.targets,在导入目标后导入 after.{solutionname}.sln.targets ,其中包括安装到 $(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\SolutionFile\ImportBefore$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\SolutionFile\ImportAfter 目录的目标。The generated project file imports before.{solutionname}.sln.targets before defining any targets and after.{solutionname}.sln.targets after importing targets, including targets installed to the $(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\SolutionFile\ImportBefore and $(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\SolutionFile\ImportAfter directories.

例如,可以在包含以下内容的名为 after.MyCustomizedSolution.sln.targets 的相同目录中创建文件,从而定义在生成 MyCustomizedSolution.sln 后写自定义日志消息的新目标 For example, you could define a new target to write a custom log message after building MyCustomizedSolution.sln by creating a file in the same directory named after.MyCustomizedSolution.sln.targets that contains

<Project>
 <Target Name="EmitCustomMessage" AfterTargets="Build">
   <Message Importance="High" Text="The solution has completed the Build target" />
 </Target>
</Project>

解决方案生成与项目生成分开进行,因此,此处的设置不会影响项目生成。The solution build is separate from the project builds, so settings here do not affect project builds.

自定义所有 .NET 生成Customize all .NET builds

维护生成服务器时,可能需要为服务器上的所有生成全局配置 MSBuild 设置。When maintaining a build server, you might need to configure MSBuild settings globally for all builds on the server. 原则上,可以修改全局 Microsoft.Common.Targets 或 Microsoft.Common.Props 文件,但有一种更好的方法。In principle, you could modify the global Microsoft.Common.Targets or Microsoft.Common.Props files, but there is a better way. 可以通过使用特定的 MSBuild 属性并添加某些自定义 .targets.props 文件,来影响特定项目类型的所有生成(如所有 C# 项目)。You can affect all builds of a certain project type (such as all C# projects) by using certain MSBuild properties and adding certain custom .targets and .props files.

若要影响通过安装 MSBuild 或 Visual Studio 控制的所有 C# 或 Visual Basic 的生成,请创建 Custom.Before.Microsoft.Common.Targets 或 Custom.After.Microsoft.Common.Targets文件(其目标将在 Microsoft.Common.targets 之前或之后运行),或创建 Custom.Before.Microsoft.Common.Props 或 Custom.After.Microsoft.Common.Props 文件 (将在 Microsoft.Common.props 之前或之后进行处理其属性)。To affect all C# or Visual Basic builds governed by an installation of MSBuild or Visual Studio, create a file Custom.Before.Microsoft.Common.Targets or Custom.After.Microsoft.Common.Targets with targets that will run before or after Microsoft.Common.targets, or a file Custom.Before.Microsoft.Common.Props or Custom.After.Microsoft.Common.Props with properties that will be processed before or after Microsoft.Common.props.

可以使用以下 MSBuild 属性指定这些文件的位置:You can specify the locations of these files by using the following MSBuild properties:

  • CustomBeforeMicrosoftCommonPropsCustomBeforeMicrosoftCommonProps
  • CustomBeforeMicrosoftCommonTargetsCustomBeforeMicrosoftCommonTargets
  • CustomAfterMicrosoftCommonPropsCustomAfterMicrosoftCommonProps
  • CustomAfterMicrosoftCommonTargetsCustomAfterMicrosoftCommonTargets
  • CustomBeforeMicrosoftCSharpPropsCustomBeforeMicrosoftCSharpProps
  • CustomBeforeMicrosoftVisualBasicPropsCustomBeforeMicrosoftVisualBasicProps
  • CustomAfterMicrosoftCSharpPropsCustomAfterMicrosoftCSharpProps
  • CustomAfterMicrosoftVisualBasicPropsCustomAfterMicrosoftVisualBasicProps
  • CustomBeforeMicrosoftCSharpTargetsCustomBeforeMicrosoftCSharpTargets
  • CustomBeforeMicrosoftVisualBasicTargetsCustomBeforeMicrosoftVisualBasicTargets
  • CustomAfterMicrosoftCSharpTargetsCustomAfterMicrosoftCSharpTargets
  • CustomAfterMicrosoftVisualBasicTargetsCustomAfterMicrosoftVisualBasicTargets

这些属性的通用版本都会影响 C# 和 Visual Basic 项目。The Common versions of these properties affect both C# and Visual Basic projects. 可以在 MSBuild 命令行中设置这些属性。You can set these properties in the MSBuild command line.

msbuild /p:CustomBeforeMicrosoftCommonTargets="C:\build\config\Custom.Before.Microsoft.Common.Targets" MyProject.csproj

可以针对不同的应用场景使用最适合的方法。The best approach depends on your scenario. 凭借 Visual Studio 扩展性,你可以自定义生成系统,并提供安装和管理自定义项的机制。Using Visual Studio Extensibility, you can customize the build system and provide a mechanism for installing and managing the customizations.

如果你有一个专用的生成服务器,并且需要确保特定目标始终在该服务器上执行的相应项目类型的所有生成上执行,则适合使用全局自定义 .targets.props 文件。If you have a dedicated build server and want to ensure that certain targets always execute on all builds of the appropriate project type that execute on that server, then using a global custom .targets or .props file makes sense. 如果需要让自定义目标仅在某些条件适用时执行,可使用其他文件位置,并(仅在需要时)通过在 MSBuild 命令行中设置相应的 MSBuild 属性设置该文件的路径。If you want the custom targets to only execute when certain conditions apply, then use another file location and set the path to that file by setting the appropriate MSBuild property in the MSBuild command line only when needed.

警告

每当 Visual Studio 生成匹配类型的任何项目时,只要它能在 MSBuild 文件夹中找到自定义文件 .targets.props,就能使用它们。Visual Studio uses the custom .targets or .props files if it finds them in the MSBuild folder whenever it builds any project of the matching type. 这可能会带来意想不到的后果,如果操作不正确,可能会导致 Visual Studio 无法在你的计算机上进行生成。This can have unintended consequences, and if done incorrectly, can disable the ability of Visual Studio to build on your computer.

自定义 C++ 生成Customize C++ builds

对于 C++ 项目,无法按相同的方式使用前面提到的自定义 .targets 和 .props 文件来覆盖默认设置 。For C++ projects, the previously mentioned custom .targets and .props files cannot be used in the same way to override default settings. Directory.Build.props 由 Microsoft.Common.props 导入 Microsoft.Cpp.Default.props,而大多数默认设置都在 Microsoft.Cpp.props 中定义;并且,由于已经定义,许多属性都不能使用“如果尚未定义”条件,但是对于在 PropertyGroup 中使用 Label="Configuration" 定义的特殊项目属性,默认设置必须不同(请参阅 .vcxproj 和 .props 文件结构) 。Directory.Build.props is imported by Microsoft.Common.props, which is imported in Microsoft.Cpp.Default.props while most of the defaults are defined in Microsoft.Cpp.props and for a number of properties a "if not yet defined" condition cannot be used, as the property is already defined, but the default needs to be different for particular project properties defined in PropertyGroup with Label="Configuration" (see .vcxproj and .props file structure).

但是,你可以使用以下属性来指定要在 Microsoft.Cpp.* 文件之前/之后自动导入的 .props 文件 :But, you can use the following properties to specify .props file(s) to be automatically imported before/after Microsoft.Cpp.* files:

  • ForceImportAfterCppDefaultPropsForceImportAfterCppDefaultProps
  • ForceImportBeforeCppPropsForceImportBeforeCppProps
  • ForceImportAfterCppPropsForceImportAfterCppProps
  • ForceImportBeforeCppTargetsForceImportBeforeCppTargets
  • ForceImportAfterCppTargetsForceImportAfterCppTargets

要自定义所有 C++ 生成的默认属性值,请创建另一个 .props 文件(例如 MyProps.props),然后在指向该文件的 Directory.Build.props 中定义 ForceImportAfterCppProps 属性 :To customize the default values of properties for all C++ builds, create another .props file (say, MyProps.props), and define the ForceImportAfterCppProps property in Directory.Build.props pointing to it:

$(MsbuildThisFileDirectory)\MyProps.props $(MsbuildThisFileDirectory)\MyProps.props

MyProps.props 会自动导入到 Microsoft.Cpp.props 的最末尾 。MyProps.props will be automatically imported at the very end of Microsoft.Cpp.props.

自定义所有 C++ 生成Customize all C++ builds

不建议自定义 Visual Studio 安装,因为无法轻松跟踪此类自定义项,但如果要扩展 Visual Studio 以自定义特定平台的 C++ 生成,则可以为每个平台创建 .targets 文件,并将这些文件作为 Visual Studio 扩展的一部分放在适用于这些平台的相应导入文件夹中。Customizing the Visual Studio installation isn't recommended, since it's not easy to keep track of such customizations, but if you're extending Visual Studio to customize C++ builds for a particular platform, you can create .targets files for each platform and place them in the appropriate import folders for those platforms as part of a Visual Studio extension.

Win32 平台的 .targets 文件 (Microsoft.Cpp.Win32.targets) 包含以下 Import 元素:The .targets file for the Win32 platform, Microsoft.Cpp.Win32.targets, contains the following Import element:

<Import Project="$(VCTargetsPath)\Platforms\Win32\ImportBefore\*.targets"
        Condition="Exists('$(VCTargetsPath)\Platforms\Win32\ImportBefore')"
/>

同一文件的末尾附近有一个相似的元素:There's a similar element near the end of the same file:

<Import Project="$(VCTargetsPath)\Platforms\Win32\ImportAfter\*.targets"
        Condition="Exists('$(VCTargetsPath)\Platforms\Win32\ImportAfter')"
/>

*%ProgramFiles32%\MSBuild\Microsoft.Cpp\v{version}\Platforms* 中的其他目标平台也存在类似的导入元素。Similar import elements exist for other target platforms in *%ProgramFiles32%\MSBuild\Microsoft.Cpp\v{version}\Platforms*.

根据平台将 .targets 文件放在适当的 ImportAfter 文件夹中后,MSBuild 会将文件导入到该平台的每个 C++ 生成中。Once you place the .targets file in the appropriate ImportAfter folder according to the platform, MSBuild imports your file into every C++ build for that platform. 如果需要,可以将多个 .targets 文件放在那里。You can put multiple .targets files there, if needed.

使用 Visual Studio 扩展性可以进行进一步的自定义,例如定义新平台。Using Visual Studio Extensibility, further customizations are possible, such as defining a new platform. 有关详细信息,请参阅 C++ 项目扩展性For more information, see C++ project extensibility.

在命令行上指定自定义导入Specify a custom import on the command line

对于要针对某个 C++ 项目的特定生成加入的自定义 .targets,请在命令行上设置 ForceImportBeforeCppTargets 和/或 ForceImportAfterCppTargets 属性。For custom .targets that you want to include for a specific build of a C++ project, set one or both of the properties ForceImportBeforeCppTargets and ForceImportAfterCppTargets on the command line.

msbuild /p:ForceImportBeforeCppTargets="C:\build\config\Custom.Before.Microsoft.Cpp.Targets" MyCppProject.vcxproj

对于全局设置(例如,要影响生成服务器上某个平台的所有 C++ 生成),有两种方法。For a global setting (to affect, say, all C++ builds for a platform on a build server), there are two methods. 首先,可以使用始终设置的系统环境变量来设置这些属性。First, you can set these properties using a system environment variable that is always set. 之所以可行,是因为 MSBuild 始终读取环境并为所有环境变量创建(或覆盖)属性。This works because MSBuild always reads the environment and creates (or overrides) properties for all the environment variables.

请参阅See also