我做了一个NuGet package,它在设计和构建时从DSL文件生成C#代码。它在Visual Studio中工作正常,但在Rider中有一些问题(我将在下面进行描述)。
在Visual Studio中
程序包为DSL文件声明custom items,并为它们分配MSBuild:Compile
Generator
元数据,每当文件更改时,它就会在Visual Studio中触发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,它在项目上公开了“重新加载项目并显示日志”操作,该操作表明Rider在项目加载时使用以下目标调用MSBuild:
请注意,该列表中缺少
CompileDesignTime
或Compile
。因此,我添加了以下目标来支持Rider:
<Target Name="GenerateZebusMessagesRiderDesignTime"
Condition="'$(BuildingByReSharper)' == 'true'"
AfterTargets="PrepareForBuild"
DependsOnTargets="GenerateZebusMessages" />
它挂接到
PrepareForBuild
所依赖的ResolveAssemblyReferences
,并调用GenerateZebusMessages
。这使Rider意识到生成的文件,但是我想解决一些问题:
问题
我想让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来重新评估项目?
最佳答案
我有两个故事供您引用-短篇小说和长篇小说=)
短篇小说
它应该在即将到来的2019.1 EAP 1中开箱即用
漫长的故事
Rider(与Visual Studio不同)在项目加载阶段不执行设计时构建。我们认为这太昂贵了(特别是对于基于.net sdk的项目)。因此,Rider会评估每个项目,然后构建一组预定义目标以获取生成的文件和程序集引用。
有时它会引起问题(例如这样的问题),因此在2019.1中,我们实现了额外的算法,该算法可扫描所有导入的目标并查找自定义的item-factory
目标。据我所知,您的目标非常适合,因此Rider可以找到它并与预定义的目标一起建立。
如果仍然无法解决问题,您仍然可以选择两种方法:
Build Tools
选项页面,因此您将能够向加载过程