如何在 Rider 中触发基于文件更改的设计时构建?
How to trigger a design-time build on file change in Rider?
我制作了一个 NuGet package,它在设计和构建时从 DSL 文件生成 C# 代码。它在 Visual Studio 中运行良好,但在 Rider 中存在一些问题(我将在下面描述)。
在Visual Studio
每次文件更改时,程序包都会在 Visual Studio 中声明 custom items for the DSL files, and assigns them a MSBuild:Compile
Generator
metadata, which triggers a design-time build。
然后,自定义目标挂钩到使用 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,它公开了对项目的 "Reload Project and Show Logs" 操作,这表明 Rider 在项目加载时使用以下目标调用 MSBuild:
GenerateAssemblyInfo;_CheckForInvalidConfigurationAndPlatform;GetFrameworkPaths;ResolvePackageDependenciesDesignTime;CollectPackageReferences;BeforeResolveReferences;ResolveAssemblyReferences;ResolveComReferences;ResolveSDKReferences;ResolveCodeAnalysisRuleSet
请注意该列表中缺少 CompileDesignTime
或 Compile
。
所以我添加了以下目标来支持 Rider:
<Target Name="GenerateZebusMessagesRiderDesignTime"
Condition="'$(BuildingByReSharper)' == 'true'"
AfterTargets="PrepareForBuild"
DependsOnTargets="GenerateZebusMessages" />
它挂钩到 ResolveAssemblyReferences
所依赖的 PrepareForBuild
,并调用 GenerateZebusMessages
。
这让 Rider 知道生成的文件,但有一些问题我想解决:
- 如果我编辑 .msg 文件,生成的 C# 代码仅在构建项目时更新,而 Rider 的代码补全直到那时才更新。
- 如果我将 .msg 文件添加到项目中,我需要重新加载项目才能将其考虑在内。构建项目在这里没有帮助。
问题
我想让 Rider 调用 MSBuild 目标并在编辑 .msg 文件或 added/removed.
时重新评估项目
我在添加文件时只在日志中发现了以下内容,但没有太大帮助:
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 来重新评估项目?
我有两个故事给你 - 一个短的和一个长的 =)
短篇小说
它应该在即将到来的 2019.1 EAP 1 中开箱即用
说来话长
Rider(与 Visual Studio 不同)在项目加载阶段不执行设计时构建。我们认为它太贵了(尤其是对于基于 .net sdk 的项目)。因此,Rider 评估每个项目,然后构建一些预定义的目标集以获得生成的文件和程序集引用。
有时它会导致问题(例如这个问题),因此在 2019.1 中,我们实施了额外的算法来扫描所有导入的目标并查找自定义 item-factory
目标。据我所知,您的目标非常适合,因此 Rider 将能够找到它并与预定义的目标一起构建。
如果它无法正常工作,您仍然有两个选择:
- 我们重写了
Build Tools
选项页面,因此您可以将任何自定义目标添加到加载过程
- 在这里提出问题:https://youtrack.jetbrains.com/newIssue?project=Rider 我会尽快解决您的问题。这些问题对我们来说具有最高优先级。
我制作了一个 NuGet package,它在设计和构建时从 DSL 文件生成 C# 代码。它在 Visual Studio 中运行良好,但在 Rider 中存在一些问题(我将在下面描述)。
在Visual Studio
每次文件更改时,程序包都会在 Visual Studio 中声明 custom items for the DSL files, and assigns them a MSBuild:Compile
Generator
metadata, which triggers a design-time build。
然后,自定义目标挂钩到使用 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,它公开了对项目的 "Reload Project and Show Logs" 操作,这表明 Rider 在项目加载时使用以下目标调用 MSBuild:
GenerateAssemblyInfo;_CheckForInvalidConfigurationAndPlatform;GetFrameworkPaths;ResolvePackageDependenciesDesignTime;CollectPackageReferences;BeforeResolveReferences;ResolveAssemblyReferences;ResolveComReferences;ResolveSDKReferences;ResolveCodeAnalysisRuleSet
请注意该列表中缺少 CompileDesignTime
或 Compile
。
所以我添加了以下目标来支持 Rider:
<Target Name="GenerateZebusMessagesRiderDesignTime"
Condition="'$(BuildingByReSharper)' == 'true'"
AfterTargets="PrepareForBuild"
DependsOnTargets="GenerateZebusMessages" />
它挂钩到 ResolveAssemblyReferences
所依赖的 PrepareForBuild
,并调用 GenerateZebusMessages
。
这让 Rider 知道生成的文件,但有一些问题我想解决:
- 如果我编辑 .msg 文件,生成的 C# 代码仅在构建项目时更新,而 Rider 的代码补全直到那时才更新。
- 如果我将 .msg 文件添加到项目中,我需要重新加载项目才能将其考虑在内。构建项目在这里没有帮助。
问题
我想让 Rider 调用 MSBuild 目标并在编辑 .msg 文件或 added/removed.
时重新评估项目我在添加文件时只在日志中发现了以下内容,但没有太大帮助:
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 来重新评估项目?
我有两个故事给你 - 一个短的和一个长的 =)
短篇小说
它应该在即将到来的 2019.1 EAP 1 中开箱即用
说来话长
Rider(与 Visual Studio 不同)在项目加载阶段不执行设计时构建。我们认为它太贵了(尤其是对于基于 .net sdk 的项目)。因此,Rider 评估每个项目,然后构建一些预定义的目标集以获得生成的文件和程序集引用。
有时它会导致问题(例如这个问题),因此在 2019.1 中,我们实施了额外的算法来扫描所有导入的目标并查找自定义 item-factory
目标。据我所知,您的目标非常适合,因此 Rider 将能够找到它并与预定义的目标一起构建。
如果它无法正常工作,您仍然有两个选择:
- 我们重写了
Build Tools
选项页面,因此您可以将任何自定义目标添加到加载过程 - 在这里提出问题:https://youtrack.jetbrains.com/newIssue?project=Rider 我会尽快解决您的问题。这些问题对我们来说具有最高优先级。