Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Post-build event always runs in MSBUILD VS2013

This is very similar to this question, except for the problem except the problem exists on MSBUILD after I fix it for VS2013. The post-build event is running even though the compiler and linker think the project is up-to-date.

Any thoughts on how to prevent the post-build event from running here?

1>Project "D:\XXX\XXX\XXX\XXX.vcxproj" on node 1 (default targets).

1>InitializeBuildStatus:
  Creating ".\..\XXX\XXX\XXX\XXX.39DEE505.tlog\unsuccessfulbuild" because "AlwaysCreate" was specified.\

ClCompile:
  All outputs are up-to-date.
  All outputs are up-to-date.
ResourceCompile:
  All outputs are up-to-date.
Link:
  All outputs are up-to-date.
  WpnSiteOverlayManager.vcxproj -> D:\XXX\XXX\XXX\XXX\..\bin\Release\XXX.dll
PostBuildEvent:
  "..\..\..\Components\DevTools\Build\BuildCommand.exe" /p "..\..\..\Products" "D:\XXX
  ....
  buildcommand completed successfully
FinalizeBuildStatus:
  Deleting file ".\..\intermediate\release\XXX\XXX.39DEE505.tlog\unsuccessfulbuild".
  Touching ".\..\intermediate\release\XXX\XXX.39DEE505.tlog\XXX.lastbuildstate".
1>Done Building Project "D:\XXX\XXX\XXX\XXX.vcxproj" (default targets).
like image 818
michael henson Avatar asked Dec 26 '22 11:12

michael henson


2 Answers

This functionality is built-in in MsBuild for .Net projects (search for PostBuildEvent in Microsoft.Common.Targets, also see here), here is a simplified version. The principle is you get a timestamp of your output file(s) before the build, and another one after the build, then compare them. If they are the same, obviously nothing was really built. There's a miriad of possible insertion points for this logic, here I just picked the link stage which should do just fine:

<Target Name="GetTimeStampBeforeLink" BeforeTargets="Link">
  <ItemGroup>
    <ProjectOutputFiles Include="$(TargetPath)" />
  </ItemGroup>
  <PropertyGroup>
    <OutputTimeStampBeforeLink>%(ProjectOutputFiles.ModifiedTime)</OutputTimeStampBeforeLink>
  </PropertyGroup>
</Target>

<Target Name="GetTimeStampAfterLink" AfterTargets="Link">
  <PropertyGroup>
    <OutputTimeStampAfterLink>%(ProjectOutputFiles.ModifiedTime)</OutputTimeStampAfterLink>
    <OutputFilesModified Condition="'$(OutputTimeStampBeforeLink)' != '$(OutputTimeStampAfterLink)'">True</OutputFilesModified>
  </PropertyGroup>
</Target>

You can insert this code right into your projectfile, but a better idea is to save it in a seperate file so you can reuse if for other projects by importing it wherever you want it. Also you can add files to check by adding to the ProjectOutputFiles ItemGroup.

Now all is left is disabling the PostBuildEvent. MsBuild already has a mechanism for that since postbuild event invokation is conditional on a propery named PostBuildEventUseInBuild, so we set this to false if output files are not modified:

<Target Name="DisablePostBuildEvent" AfterTargets="GetTimeStampAfterLink">
  <PropertyGroup>
    <PostBuildEventUseInBuild Condition='"$(OutputFilesModified)' != 'True'">false</PostBuildEventUseInBuild>
  </PropertyGroup>
</Target>
like image 103
stijn Avatar answered Jan 01 '23 17:01

stijn


A slightly simpler variation on stjin's answer:

<Target Name="DisablePostBuildEvent" AfterTargets="Link" BeforeTargets="PostBuildEvent">
  <PropertyGroup>
    <PostBuildEventUseInBuild Condition="'$(LinkSkippedExecution)' == 'True'">false</PostBuildEventUseInBuild>
  </PropertyGroup>
</Target>

This only executes the post build event if the linker actually executed.

like image 31
Kim Avatar answered Jan 01 '23 16:01

Kim