MSBuild增量构建生成.cs文件后二次构建仍触发编译如何解决
问题原因
你的问题本质是动态修改编译输入项的时机晚于MSBuild增量检查的计算时机,导致两次时间戳校验不同步:
- 首次构建时,MSBuild先完成全局项的计算,此时还没有
$(MyOutput)对应的Compile项,CoreCompile的增量检查先记录了初始状态;随后MyCodeGen生成文件并动态添加Compile项,CoreCompile运行编译该文件,此时记录的最新状态并没有把该文件的生成时间纳入前置校验。 - 第二次构建时,MyCodeGen的输入输出校验通过不运行,但CoreCompile的增量检查会读取到
$(MyOutput)的修改时间晚于上次CoreCompile运行的记录时间,因此会触发重新编译。 - 第三次构建时,所有时间戳全部对齐,才会提示最新。
解决方案
方案1(推荐):提前声明生成文件为编译输入
移除Target内部动态增删Compile项的逻辑,提前在全局ItemGroup中声明该生成文件为编译输入,让MSBuild在初始化阶段就识别到编译依赖该文件,自动同步增量检查逻辑。
修改后的完整配置:
<ItemGroup> <MyInput Include="$(MyInput)" /> <UpToDateCheckInput Include="@(MyInput)" /> <UpToDateCheckBuilt Include="$(MyOutput)" /> <!-- 提前声明生成的代码文件为编译输入 --> <Compile Include="$(MyOutput)" /> </ItemGroup> <Target Name="MyCodeGen" BeforeTargets="CoreCompile" DependsOnTargets="ResolveReferences" Inputs="@(MyInput);$(MSBuildThisFileFullPath);$(MyCodegenExe)" Outputs="$(MyOutput)"> <Exec Command="$(MyCodegenExe) $(MyCodegenParams)" /> </Target>
说明:
- 将Target的触发时机从
PreBuildEvent前调整到CoreCompile前,确保生成动作在编译输入校验前完成,MSBuild会自动将生成文件的修改时间纳入CoreCompile的增量检查范围。 - 提前声明Compile项后,MSBuild会自动识别到该文件需要由MyCodeGen Target生成,不需要手动处理增删逻辑,避免时间戳校验不同步的问题。
可选方案(如果必须在Target中动态添加):
如果有场景必须在Target运行时才能确定生成的文件路径,可以在添加Compile项的同时,将该文件同步到CoreCompile的输入列表中,对齐增量检查逻辑:
<ItemGroup> <MyInput Include="$(MyInput)" /> <UpToDateCheckInput Include="@(MyInput)" /> <UpToDateCheckBuilt Include="$(MyOutput)" /> </ItemGroup> <Target Name="MyCodeGen" BeforeTargets="CoreCompile" DependsOnTargets="ResolveReferences" Inputs="@(MyInput);$(MSBuildThisFileFullPath);$(MyCodegenExe)" Outputs="$(MyOutput)"> <Exec Command="$(MyCodegenExe) $(MyCodegenParams)" /> <ItemGroup> <Compile Remove="$(MyOutput)" /> <Compile Include="$(MyOutput)"> <!-- 标记为生成文件,避免增量检查误判 --> <Generated>true</Generated> </Compile> <!-- 同步更新CoreCompile的输入列表 --> <CoreCompileInput Include="$(MyOutput)" /> </ItemGroup> </Target>
两种方案都可以实现第二次构建时直接识别为全部最新的效果,优先推荐第一种提前声明的方案,逻辑更简洁、兼容性更好。
内容的提问来源于stack exchange,提问作者Max Toro
相关产品推荐
相关产品推荐

