5

在项目文件 / MSBuild / NuGet 包中编写扩展编译的时候,正确使用 props 文件和 targe...

 2 years ago
source link: https://blog.walterlv.com/post/write-msbuild-codes-into-props-or-targets.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

在项目文件 / MSBuild / NuGet 包中编写扩展编译的时候,正确使用 props 文件和 targets 文件

发布于 2019-07-01 15:54
更新于 2021-06-07 07:12

.NET 扩展编译用的文件有 .props 文件和 .targets 文件。不给我选择还好,给了我选择之后我应该使用哪个文件来编写扩展编译的代码呢?


如果你不了解 .props 文件或者 .targets 文件,可以阅读下面的博客:

具体的例子有下面这些博客。不过大概阅读一下就好,这只是 .props 和 .targets 文件的一些应用。文章比较长,你可以考虑稍后阅读。

当我们创建的 NuGet 包中包含 .props 和 .targets 文件的时候,我们相当于在项目文件 csproj 的两个地方添加了 Import 这些文件的代码。

<Project Sdk="Microsoft.NET.Sdk">

  <!-- 本来是没有下面这一行的,我只是为了说明 NuGet 相当于帮我们添加了这一行才假装写到了这里。 -->
  <Import Project="$(NuGetPackageRoot)walterlv.samplepackage\0.8.3-alpha\build\Walterlv.SamplePackage.props" Condition="Exists('$(NuGetPackageRoot)walterlv.samplepackage\0.8.3-alpha\build\Walterlv.SamplePackage.props')" />

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFrameworks>netcoreapp3.0</TargetFrameworks>
  </PropertyGroup>

  <!-- 本来是没有下面这一行的,我只是为了说明 NuGet 相当于帮我们添加了这一行才假装写到了这里。 -->
  <Import Project="$(NuGetPackageRoot)walterlv.samplepackage\0.8.3-alpha\build\Walterlv.SamplePackage.targets" Condition="Exists('$(NuGetPackageRoot)walterlv.samplepackage\0.8.3-alpha\build\Walterlv.SamplePackage.targets')" />

</Project>

如果你安装的多份 NuGet 包都带有 .props 和 .targets 文件,那么就相当于帮助你 Import 了多个:

<Project Sdk="Microsoft.NET.Sdk">

  <!-- 本来是没有下面这一行的,我只是为了说明 NuGet 相当于帮我们添加了这一行才假装写到了这里。 -->
  <Import Project="$(NuGetPackageRoot)walterlv.samplepackage1\0.8.3-alpha\build\Walterlv.SamplePackage1.props" Condition="Exists('$(NuGetPackageRoot)walterlv.samplepackage1\0.8.3-alpha\build\Walterlv.SamplePackage1.props')" />
  <Import Project="$(NuGetPackageRoot)walterlv.samplepackage2\0.5.1-beta\build\Walterlv.SamplePackage2.props" Condition="Exists('$(NuGetPackageRoot)walterlv.samplepackage2\0.5.1-beta\build\Walterlv.SamplePackage2.props')" />

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFrameworks>netcoreapp3.0</TargetFrameworks>
  </PropertyGroup>

  <!-- 本来是没有下面这一行的,我只是为了说明 NuGet 相当于帮我们添加了这一行才假装写到了这里。 -->
  <Import Project="$(NuGetPackageRoot)walterlv.samplepackage1\0.8.3-alpha\build\Walterlv.SamplePackage1.targets" Condition="Exists('$(NuGetPackageRoot)walterlv.samplepackage1\0.8.3-alpha\build\Walterlv.SamplePackage1.targets')" />
  <Import Project="$(NuGetPackageRoot)walterlv.samplepackage2\0.5.1-beta\build\Walterlv.SamplePackage2.targets" Condition="Exists('$(NuGetPackageRoot)walterlv.samplepackage2\0.5.1-beta\build\Walterlv.SamplePackage2.targets')" />

</Project>

于是,什么代码写到 .props 里而什么代码写到 .targets 里就一目了然了:

  1. 如果你是定义属性或者为属性设置初值,那么请写到 .props 里面
    • 这样,所有的 NuGet 包或者扩展的编译流程都将可以访问到你设置的属性的值
  2. 如果你是使用属性,或者按条件设置属性,那么请写到 .targets 里面
    • 因为这个时候多数的属性已经初始化完毕,你可以使用到属性的值了
  3. 如果你写的是编译目标(Target),那么请写到 .targets 里面
    • 编译目标是扩展编译的,通常都是使用属性
    • 也会有一些产生属性的,但那都是需要在编译期间产生的属性,其他依赖需要使用 DependsOn 等属性来获取

例如下面的属性适合写到 .props 里面。这是一个设置属性初始值的地方:

<Project>

  <PropertyGroup>
    <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>

    <!-- 当生成 WPF 临时项目时,不会自动 Import NuGet 中的 props 和 targets 文件,这使得在临时项目中你现在看到的整个文件都不会参与编译。
       然而,我们可以通过欺骗的方式在主项目中通过 _GeneratedCodeFiles 集合将需要编译的文件传递到临时项目中以间接参与编译。
       WPF 临时项目不会 Import NuGet 中的 props 和 targets 可能是 WPF 的 Bug,也可能是刻意如此。
       所以我们通过一个属性开关 `ShouldFixNuGetImportingBugForWpfProjects` 来决定是否修复这个错误。-->
    <ShouldFixNuGetImportingBugForWpfProjects Condition=" '$(ShouldFixNuGetImportingBugForWpfProjects)' == '' ">True</ShouldFixNuGetImportingBugForWpfProjects>

  </PropertyGroup>

</Project>

这个属性的含义你可以在我的另一篇博客中找到:从零开始制作 NuGet 源代码包(全面支持 .NET Core / .NET Framework / WPF 项目)

而下面的属性适合写到 .targets 里面,因为这里使用到了其他的属性:


<Project>

  <PropertyGroup>
    <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>

    <!-- 因为这里使用到了 `Configuration` 属性,需要先等到此属性已经初始化完成再使用,否则我们会拿到非预期的值。 -->
    <ShouldOptimizeDebugging> Condition=" '$(Configuration)' == 'Debug' ">True</ShouldOptimizeDebugging>

  </PropertyGroup>

</Project>

本文会经常更新,请阅读原文: https://blog.walterlv.com/post/write-msbuild-codes-into-props-or-targets.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

如果你想持续阅读我的最新博客,请点击 RSS 订阅,或者前往 CSDN 关注我的主页

知识共享许可协议 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 ([email protected])


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK