我有一个自定义.targets
文件,用于支持编译后代码生成。我重写了一些目标,目的是让AfterBuild
任务运行代码生成器,CoreBuild
再次调用,然后进行尾递归,直到结果收敛到一个定点或需要太多迭代。(我认为我从未见过它需要超过 3 次编译才能收敛,但我使用 5 作为限制。)
在某些方面,这是一个笨拙的 hack,尤其是通过CycleDepth
同时使用来打破无限循环并防止 MSBuild 因为属性没有更改而跳过重复的任务,但它适用于其主要预期用例:生成代码以实现对象序列化方法并通过部分类机制将它们合并,作为一种优化以避免在运行时基于反射的序列化。但是,我遇到了一种中断的情况:如果使用/m
(parallel) 选项针对解决方案调用 MSBuild,则构建会可怕地死掉:在我看来,好像应该是迭代被同时调用。
有没有办法在不破坏并行 MSBuild 的情况下实现这种递归?
由于需要同时针对标准和紧凑框架,我在某种程度上锁定了 3.5 版本;优化对于在较慢的 Compact Framework 设备上实现足够的速度是必要的。
<Target Name="BeforeCompile" Condition="Exists('$(ProjectDir)CodeGenerationPostBuild.xml')">
<PropertyGroup>
<AssemblyTimestampBeforeCompile>%(IntermediateAssembly.ModifiedTime)</AssemblyTimestampBeforeCompile>
</PropertyGroup>
</Target>
<Target Name="AfterCompile" Condition="Exists('$(ProjectDir)CodeGenerationPostBuild.xml')">
<PropertyGroup>
<AssemblyTimestampAfterCompile>%(IntermediateAssembly.ModifiedTime)</AssemblyTimestampAfterCompile>
</PropertyGroup>
</Target>
<Target Name="AfterBuild" Condition="Exists('$(ProjectDir)CodeGenerationPostBuild.xml') and ('$(AssemblyTimestampBeforeCompile)'!='$(AssemblyTimestampAfterCompile)')">
<Exec WorkingDirectory="$(ProjectDir)" Command=""$(SolutionDir)..\CodeGen\CodeGeneration.Engine\bin\$(ConfigurationName)\CodeGeneration.Engine.exe" "$(ProjectDir)CodeGenerationPostBuild.xml" Command=Build ConfigurationName=$(ConfigurationName)" IgnoreExitCode="true">
<Output TaskParameter="ExitCode" PropertyName="PostBuildExitCode" />
</Exec>
<Error Condition="$(PostBuildExitCode) == 2" Code="BS0002" Text="Read-only generated code file found; did it get checked in again?" />
<Error Condition="$(PostBuildExitCode) == 99" Code="BS0099" Text="Error in code generation; see detailed build output." />
<Error Condition="'$(CycleDepth)' == 'xxxxx' And $(PostBuildExitCode) != 0" Code="BS1000" Text="Compilation taking too many iterations to converge. Do you have [AssemblyVersion("1.0.*")] in your AssemblyInfo.cs?" />
<MSBuild Condition="'$(CycleDepth)' != 'xxxxx' And $(PostBuildExitCode) == 1" Projects="$(ProjectPath)" Targets="CoreBuild; AfterBuild" Properties="CycleDepth=$(CycleDepth)x" />
</Target>