16

I'm trying to get some pre-build steps to work in a C++ project in Visual Studio 2012 but they do not get invoked (while I'm pretty sure the same techniques were OK in Visual Studio 2010). Command line builds behave exactly the same.

This is the end of the project file; the file was generated using Visual Studio and then I just added the last couple of lines:

<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Target Name="BeforeBuild">
  <Message Text="### BeforeBuild ###" />
</Target>
<Target Name="BeforeCompile">
  <Message Text="### BeforeCompile ###" />
</Target>
<Target Name="AfterBuild">
  <Message Text="### AfterBuild ###" />
</Target>

and here's the output:

Project "d:\temp\temp.vcxproj" on node 1 (default targets).
InitializeBuildStatus:
  Creating "Debug\temp.unsuccessfulbuild" because "AlwaysCreate" was specified.
AfterBuild:
  AfterBuild
FinalizeBuildStatus:
  Deleting file "Debug\temp.unsuccessfulbuild".
  Touching "Debug\temp.lastbuildstate".

So only AfterBuild is considered and the others are ignored. Looking into this I found this PropertyGroup in Microsoft.BuildSteps.targets:

<BuildDependsOn>
  _PrepareForBuild;
  $(BuildSteps);
  AfterBuild;
  FinalizeBuildStatus;
</BuildDependsOn>

Shouldn't this also have BeforeBuild and the BuildEvent targets? Or is something wrong with my MSBuild install causing it to use this BuildSteps.targets file instead of something else?

Solution

As Alexey points out, using Before/AfterTarget provides a usable workaround. You just have to take care of which targets to use, but this is easy by looking at the BuildSteps file. This seems to work fine for now:

<Target Name="BeforeBuild" BeforeTargets="PrepareForBuild">
  <Message Text="### BeforeBuild ###" />
</Target>
<Target Name="BeforeCompile" BeforeTargets="BuildCompile">
  <Message Text="### BeforeCompile ###" />
</Target>
<Target Name="AfterBuild" AfterTargets="Build">
  <Message Text="### AfterBuild ###" />
</Target>
Alexey Shcherbak
  • 3,394
  • 2
  • 27
  • 44
stijn
  • 34,664
  • 13
  • 111
  • 163

1 Answers1

20

I have same msbuild targets as you described, so I think your msbuild installation is fine.

Looks like they decide to make some cleanup to targets and dependencies ( not sure if this issue related to VS version, VS just using same targets, provided by msbuild). BeforeBuild and other targets still exists in Microsoft.common.targets. I suppose it just reserved for .NET projects (I never played with C++ ones, so I don't know, how to build a pipeline there).

Anyway whether it works or not on previous versions, your problem can be solved much easier - just use new attributes BeforeTargets\AfterTargets for MSBuild 4.0 and hook your targets directly on whatever you want:

<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Target Name="BeforeBuild" BeforeTargets="Build">
     <Message Text="### BeforeBuild ###" Importance="high" />
</Target>
<Target Name="BeforeCompile" BeforeTargets="Compile">
    <Message Text="### BeforeCompile ###" Importance="high" />
</Target>
<Target Name="AfterBuild" AfterTargets="Build">
    <Message Text="### AfterBuild ###" Importance="high" />
</Target>
peterh
  • 11,875
  • 18
  • 85
  • 108
Alexey Shcherbak
  • 3,394
  • 2
  • 27
  • 44
  • +1 for getting me on the right track; however you'd have to use different targets to get the desired results: with the steps you post, `AfterBuild` will get executed *before* `BeforeBuild` because the `Build` target is actually the last one executed since all other targets depend on it, and hence `BeforeBuild` is also not invoked before but after the build. `PrepareForBuild` seems like a better candidate. – stijn Dec 10 '12 at 09:15
  • 1
    I mentioned that this is valid for msbuild 4.0 and higher. AfterBuild (probably you should change target name to more unique, so it will not override any already existed targets and will be executed only as hooked) will be executed after build because it uses not DependsOn attribute mechanism (old one), but new and more handy one with after-before hooks. If you are still using DependsOn - you need to override this property and take care of targets execution order by yourself. Initial code was only provided for "illustration" purposes – Alexey Shcherbak Dec 10 '12 at 10:06
  • 2
    I took the freedom to add `Importance="high"`. That's required to ensure [messages make it to the console](https://stackoverflow.com/questions/10516336) with default [verbosity settings](https://stackoverflow.com/questions/3352228). Without it, it looks like the targets are not executed, which is very confusing when wrestling with msbuild. – Christian Aichinger May 07 '15 at 20:06