如何在Rider中基于文件更改触发设计时构建?

时间:2019-02-18 10:31:56

标签: .net msbuild resharper rider

我制作了一个NuGet package,它可以在设计和构建时从DSL文件生成C#代码。它在Visual Studio中可以正常工作,但在Rider中有一些问题(我将在下面介绍)。

在Visual Studio中

该程序包为DSL文件声明custom items,并为它们分配MSBuild:Compile Generator元数据,每次文件更改时,它就会在Visual Studio中触发design-time build。 / p>

然后,一个自定义目标通过BeforeTargets="CoreCompile"挂接到构建。它生成C#代码,并将Compile项添加到项目中。该目标可在常规和设计时构建中运行,并支持incremental builds以避免不必要的工作。

以下是相关的(经过简化和注释)的MSBuild代码:

props文件:

<Project>

  <!-- Define the item type with its default metadata -->
  <ItemDefinitionGroup>
    <ZebusMessages>
      <Generator>MSBuild:Compile</Generator>
    </ZebusMessages>
  </ItemDefinitionGroup>

  <!-- Make the item type user-visible in VS -->
  <ItemGroup>
    <AvailableItemName Include="ZebusMessages" />
    <PropertyPageSchema Include="$(MSBuildThisFileDirectory)ZebusMessages.xml" />
  </ItemGroup>

  <!-- Include all .msg files by default -->
  <ItemGroup>
    <ZebusMessages Include="**\*.msg" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
  </ItemGroup>

</Project>

targets文件:

<Project>

  <ItemGroup>
    <!-- Add a GeneratorTargetPath metadata for the target file -->
    <ZebusMessages Update="@(ZebusMessages)" GeneratorTargetPath="$([MSBuild]::ValueOrDefault('$(IntermediateOutputPath)ZebusMessages/%(RecursiveDir)%(FileName)%(Extension).cs', '').Replace('\', '/'))" />

    <!-- Remove all None items for .msg files -->
    <None Remove="**\*.msg" />
  </ItemGroup>

  <Target Name="GenerateZebusMessages"
          BeforeTargets="CoreCompile"
          Condition="'@(ZebusMessages)' != ''"
          Inputs="@(ZebusMessages)"
          Outputs="@(ZebusMessages->'%(GeneratorTargetPath)')">

    <!-- Generate output files -->
    <GenerateZebusMessagesTask InputFiles="@(ZebusMessages)" />

    <ItemGroup>
      <!-- Add the output items -->
      <Compile Include="@(ZebusMessages->'%(GeneratorTargetPath)')" Visible="false" />
      <FileWrites Include="@(ZebusMessages->'%(GeneratorTargetPath)')" />
    </ItemGroup>
  </Target>

</Project>

完整文件为available here

在骑士中

在Rider 2018.3.3中进行了测试:

这在Rider中不是开箱即用的,因为它似乎没有像VS那样触发设计时构建。

起初,Rider完全不了解生成的C#文件,这导致它在引用生成的类的代码中显示错误。

我使用了Rider的internal mode,它公开了项目上的“重新加载项目并显示日志”操作,这表明Rider在项目加载时调用了具有以下目标的MSBuild:

  

GenerateAssemblyInfo; _CheckForInvalidConfigurationAndPlatform; GetFrameworkPaths; ResolvePackageDependenciesDesignTime; CollectPackageReferences; BeforeResolveReferences; ResolveAssemblyReferences; ResolveComReferences; ResolveSDKReferences; ResolveCodeAnalysisRuleSet

请注意,该列表中缺少CompileDesignTimeCompile

所以我添加了以下目标来支持Rider:

  <Target Name="GenerateZebusMessagesRiderDesignTime"
          Condition="'$(BuildingByReSharper)' == 'true'"
          AfterTargets="PrepareForBuild"
          DependsOnTargets="GenerateZebusMessages" />

它与PrepareForBuild所依赖的ResolveAssemblyReferences挂钩,并调用GenerateZebusMessages

这使Rider知道生成的文件,但是我想解决一些问题:

  • 如果我编辑.msg文件,则仅在构建项目时才更新生成的C#代码,并且直到那时Rider的代码完成都不是最新的。
  • 如果将.msg文件添加到项目中,则需要重新加载该项目才能将其考虑在内。在这里建立项目无济于事。

问题

我想让Rider调用MSBuild目标并在编辑或添加/删除.msg文件时重新评估该项目。

添加文件时,我仅在日志中找到以下内容,但并没有太大帮助:

10:54:05.076 |I| ProjectModel                   | RequestBuilder thread:7        | Add item ZebusMessages = 'OtherFile.msg'...
10:54:05.076 |I| ProjectModel                   | RequestBuilder thread:7        | Item matches to a wildcard pattern, mark project as dirty
10:54:05.095 |I| ProjectModel                   | RequestBuilder thread:7        | Project file content requested: ZebusMessages.csproj
10:54:08.330 |I| ProjectModel                   | RequestBuilder thread:7        | Item with EvaluatedInclude 'OtherFile.msg' was already changed. Perform project reevaluation before processing.
10:54:08.361 |I| ProjectModel                   | RequestBuilder thread:7        | Project 'ZebusMessages.csproj' was reevaluated in 22 ms, EvaluationCounter: 9

在此时间范围内,日志中没有其他提到MSBuild。

当给定文件类型更改时,是否有可能在Rider中触发类似于设计时构建的内容?

或更笼统地说,在什么情况下Rider会调用MSBuild重新评估项目?

1 个答案:

答案 0 :(得分:2)

我有两个故事适合您-短篇小说和长篇小说=)

短篇小说

它应该在即将到来的2019.1 EAP 1中开箱即用

漫长的故事

Rider(与Visual Studio不同)在项目加载阶段不执行设计时构建。我们认为这太昂贵了(特别是对于基于.net sdk的项目)。因此,Rider会评估每个项目,然后构建一组预定义目标以获取生成的文件和程序集引用。

有时它会引起问题(例如此问题),因此在2019.1中,我们实现了附加算法,该算法可扫描所有导入的目标并寻找自定义item-factory目标。据我所知,您的目标非常适合,因此Rider可以找到它并与预定义目标一起建立。

如果无法正常工作,您仍然有两个选择:

  1. 我们已经重写了Build Tools选项页,因此您可以将任何自定义目标添加到加载过程中
  2. 在此处提出问题:https://youtrack.jetbrains.com/newIssue?project=Rider,我们将尽力解决您的问题。这些问题对我们来说是最优先的。