MSBuild: How to ensure AfterBuild target always runs in a C++ project - visual-studio

I have added the following AfterBuild task to a .vcxproj file:
<Target Name="AfterBuild">
<Message Text="Hi" Importance="high" />
</Target>
It seems to run only if the the C++ code is built (or if I do a rebuild):
1>------ Rebuild All started: Project: ConsoleApplication1, Configuration: Debug Win32 ------
1> stdafx.cpp
1> SomeClass.cpp
1> ConsoleApplication1.vcxproj ->
1> Hi
D:\Projects\CppTest\Debug\ConsoleApplication1.lib
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========
It doesn't run when the the C++ code is up-to-date:
========== Build: 0 succeeded, 0 failed, 1 up-to-date, 0 skipped ==========
How can I make it always run? I'm using Visual Studio 2015.

The line
========== Build: 0 succeeded, 0 failed, 1 up-to-date, 0 skipped ==========
means that Visual Studio didn't run MSBuild at all.
For incremental builds VS uses File Tracker to intercept file operations being performed by compiler and linker. Results can be fould in ProjName.tlog folder. In subsequent builds VS checks dates of files listed in .read and .write files and decides whether to run MSBuild. This feature is described in Hashimi S., Bartholomew S. - Using MSBuild, 2nd Edition - 2013, "File Tracker" chapter.
Some of possible solutions:
Use FileTracker API in your custom build tool.
Manually write file name(s) produced by your tool in some .write file (this solution is simple but is not guaranteed to work in future VS versions).
Build your solution by MSBuild instead VS.
Build your solution from bat-file, which calls devenv first then your tool.

I got around this issue by adding the following lines to my .vcxproj file:
<PropertyGroup>
<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
</PropertyGroup>
It seems to force the IDE to actually run MSBuild.
I tested it in Visual Studio 2015. Adding the same lines to an imported .targets file did not help.

There is a setting "Run the post-build event:" in project properties in Visual Studio, and you need to set it to: "Always" for the post-build event to run always.
I guess it's now set to "On successful build".

Build your project with detailed logging (/v:detailed or /v:diag) and find the target which being run last but present in both cases (lets say it's a made up target "FinalCleanup"), then hook your post-build target like this rather than by the special name
<Target Name="RunMyLastTarget" AfterTargets="FinalCleanup">
<Message Text="Hi" Importance="high" />
</Target>

I finally went with Custom Build Step. To ensure that it always runs I set the Outputs field to some dummy file path. Since the dummy file path is never present, the Custom Build Step always runs. It is hacky, but it gets the job done.

Related

Execute custom MSBuild task always after build process

I created a custom Task that executes after the build operation.
<Target Name="AfterBuild" />
<Target Name="MyTarget"
AfterTargets="AfterBuild">
<MyTask ... />
</Target>
QUESTION: Is it possible to execute the task, if the build operation was triggered, but did not perform, because there are no changes in the project / no need to build again?
In other words: I want to execute the task always at the end of the build process, even if the project was not built again.
UPDATE: Using AfterTargets="Build" or setting the property <DisableFastUpToDateCheck>true</DisableFastUpToDateCheck> does not help.
After triggering the Build process a second time, I only get the Output: Build: 0 succeeded, 0 failed, 1 up-to-date, 0 skipped
Is it possible to execute the task, if the build operation was triggered, but did not perform, because there are no changes in the project / no need to build again?
If I understand you correctly, you can define this property in your project file:
<PropertyGroup>
<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
</PropertyGroup>
Note: This method seems that Visual Studio is bypassing normal up-to-date checks of MSBuild and using some sort of custom check that is faster, but has a side effect of breaking customized build targets.
Update:
Not sure the reason why this method not work on your project, let me make the answer more detail:
Define the property in your project file:
Add the custom MSBuild task with some messages info.
Build the project, check the output(log file verbosity is Normal).
Build the project again, check the output again.
If I use AfterTargets="Build" instead of AfterBuild, the message is written to the Output window every time I build the solution (.NET Core Console App with a .NET Standard Class Libary).
<Target Name="MyAfterBuild" AfterTargets="Build">
<Message Importance="High" Text="Hello World!" />
</Target>

Why does Visual Studio (2010) run two builds for a BizTalk Server Project?

I'm using Visual Studio 2010 and BizTalk 2010.
When I add a new Empty BizTalk Server Project and build it, I get the following output:
------ Build started: Project: ThrowAway1, Configuration: Debug Any CPU ------
ThrowAway1 -> c:\...\Projects\ThrowAway1\ThrowAway1\bin\Debug\ThrowAway1.dll
ThrowAway1 -> c:\...\Projects\ThrowAway1\ThrowAway1\bin\Debug\ThrowAway1.dll
========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========
I already tried deactivating the release build. But I still get two build events - which also affects the post build event.
With a default console application I get only one build event.
My goal is to run my own deployment PowerShell script in the post build event. The script is coming along nicely but it is called two times by this behavior.
This appears to be the expected behavior of a BizTalk Project.
I'm only speculating that it's because many BizTalk artifacts are compiled in a two step process. Orchestrations to C# then C# to the output Assembly for example.
The only thing I can recommend is to either make the script deterministic or maybe a side project that runs the post build for the entire Solution.
You can also investigate the BizTalk Deployment Framework: http://biztalkdeployment.codeplex.com/
As a pragmatic solution:
Checking the .btproj MSBuild file and its imports
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\BizTalk\BizTalkC.targets" />
where BizTalkC.targets imports
<Import Project="$(MSBuildExtensionsPath)\Microsoft\BizTalk\BizTalkCommon.targets" />
shows the usage of $(SecondBuild) in BizTalkCommon.targets.
This can be used in the post build event:
if "$(SecondBuild)"=="true" (
rem Run script.
)
For the first build $(SecondBuild) will be empty/undefined.

Determine whether it's a build or rebuild in .cmd script called in prelink step inside Visual Studio

How can a .cmd script run from within a Visual Studio (2005, 2008, 2010, 2012 and 2013 respectively) project's pre-link stage determine whether this is a full rebuild (Build.RebuildSolution/Build.RebuildOnlyProject) or "ordinary" build (Build.BuildSolution/Build.BuildOnlyProject)?
This is an external script (LuaJIT, if you must know) and I don't want to rebuild the library every single build of the project. Instead I'd like to limit the complete rebuild to situations where I choose exactly that option.
How can a .cmd script run from within a Visual Studio (2005, 2008, 2010, 2012 and 2013 respectively) project's pre-link stage determine whether this is a full rebuild ... or "ordinary" build ... ?
I do not know if the exact thing that you are asking can be done - perhaps someone else knows how to do it. I will, however, suggest an alternate approach.
My approach is to remove the build of the Lua library from the pre-link step to a separate Visual Studio NMake project. If you create an NMake project, you will be able to know which type of build (build or rebuild) is occurring.
Note that later versions of Visual Studio simply refer to the project type as "Make". For discussion purposes here, I will refer to the project type as "NMake". I believe this is just a naming difference, and that the underlying build project remains the same between the two versions.
As a simple test, I created two Visual Studio applications: 1) an NMake project that calls a batch file to create a static library, and 2) a console application that consumes the library from step 1.
The NMake Project
In Visual Studio, if you create a new NMake project, you will see a dialog that allows you to provide MS-DOS commands:
As you can see, there are commands for: Build, Clean, Rebuild, and others. I don't have a screen shot of the above dialog with my commands, but here is my NMake project's properties:
My Build command just checks for the existence of the output file (lua.lib). If it does not exist, then it calls the rebuild.bat batch file. My Rebuild command always calls the batch file. My Clean command just deletes the output. I am not really sure what the Output command is used for, but I just filled in the path to the build output (lua.lib).
Now if you do a build, the lua.lib file will only be created if it is not there. If it is already there, nothing is done. If you do a rebuild, then a new lua.lib file is created.
The Console Application
In my console application, I added a reference to the NMake project - this way the NMake project is built prior to the console application. Here is the console application's reference page:
I also added the lua.lib file as an input during the application's link stage:
When the console application is built (during a build), it will build the NMake project if needed, and use the output (lua.lib) during the linker stage. When the console application is rebuilt (during a rebuild), it will also rebuild the NMake project.
Other Thoughts
My screen shots above only show the debug version of the properties. Your projects will have to account for the release version. There probably is a VS macro to handle this, but I am not sure since it has been ages since I've done anything with C/ C++.
In my testing above I use a single build batch file for both the build and rebuild. Obviously, you could do the same or you could use different batch files.
It may be a bit of a hack, but in .csproj file there are sections
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
You can set an variable from BeforeBuild and retrieve it from cmd script. Later on reset this variable in AfterBuild and you should be good to go.
Ok, this is going to be a long one.
First of all - do not take my code 'as is' - it is terrible one with lots of hacks, I had no idea msbuild is so broken by default (it seems at work I have access to waaaay more commands that make life easier). And another thing - it seems vcxproj is broken at some poin - I was not able to integrate the way I wanted with only BeforeRebuild and AfterRebuild targets - I had to redefine hole Rebuild target (it is located in C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets)
So, the idea is the following: when a Rebuild is happening we create an anchor. Then, during PreLink stage we execute cmd which is able to use created anchor. If the anchor is in place - we deal with Rebuild, if there is no anchor - it is a simple Build. After Rebuild is done - we delete the anchor.
modifications in vcxproj file:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
....
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
....
<PreLinkEventUseInBuild>true</PreLinkEventUseInBuild>
....
</PropertyGroup>
....
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
.....
<PreLinkEvent>
<Command>D:\PreLink\b.cmd</Command>
</PreLinkEvent>
.....
</ItemDefinitionGroup>
.....
<Target Name="BeforeRebuild">
<Exec Command="echo 2 > D:\PreLink\2.txt" />
</Target>
<Target Name="AfterRebuild">
<Exec Command="del D:\PreLink\2.txt" />
</Target>
<!-- This was copied from MS file -->
<PropertyGroup>
<_ProjectDefaultTargets Condition="'$(MSBuildProjectDefaultTargets)' != ''">$(MSBuildProjectDefaultTargets)</_ProjectDefaultTargets>
<_ProjectDefaultTargets Condition="'$(MSBuildProjectDefaultTargets)' == ''">Build</_ProjectDefaultTargets>
<RebuildDependsOn>
BeforeRebuild;
Clean;
$(_ProjectDefaultTargets);
AfterRebuild;
</RebuildDependsOn>
<RebuildDependsOn Condition=" '$(MSBuildProjectDefaultTargets)' == 'Rebuild' " >
BeforeRebuild;
Clean;
Build;
AfterRebuild;
</RebuildDependsOn>
</PropertyGroup>
<Target
Name="Rebuild"
Condition=" '$(_InvalidConfigurationWarning)' != 'true' "
DependsOnTargets="$(RebuildDependsOn)"
Returns="$(TargetPath)"/>
<!-- End of copy -->
</Project>
And the cmd looks like this:
if exist 2.txt (
echo Rebuild818181
) else (
echo Build12312312
)
The output from Output window:
1>Task "Exec" (TaskId:41)
1> Task Parameter:Command=D:\PreLink\b.cmd
1> :VCEnd (TaskId:41)
1> Build12312312 (TaskId:41)
Things to improve:
Use normal variables instead of external file (it seems MsBuild extension pack should do it)
Probably find a way to override only BeforeRebuild and AfterRebuild instead of the hole Rebuild part
It is much easier. Just add the following target to your build file or visual Studio Project
<Target Name="AfterRebuild">
<Message Text="AFTER REBUILD" Importance="High" />
<!--
Do whatever Needs to be done on Rebuild - as the message shows in VS Output
window it is only executed when an explicit rebuild is triggered
-->
</Target>
If you want a two step solution use this as a template:
<PropertyGroup>
<IsRebuild>false</IsRebuild>
</PropertyGroup>
<Target Name="BeforeRebuild">
<Message Text="BEFORE REBUILD" Importance="High" />
<PropertyGroup>
<IsRebuild>true</IsRebuild>
</PropertyGroup>
</Target>
<Target Name="BeforeBuild">
<Message Text="BEFORE BUILD: IsRebuild: $(IsRebuild)" Importance="High" />
</Target>

MSBuild task to Build other solution projects fails in VS but works with MSBuild.exe command line

I have a custom MSBuild task which among other things adds embedded resources to other projects in the solution. After adding the resources I'd like to then build those projects, but found I can't get this working within Visual Studio.
To test, I stripped out the custom task entirely and redefined a simple AfterBuild target in the web project of a Silverlight solution. The target uses the MSBuild task to build the Silverlight application project in the solution, and looks like this:
<Target Name="AfterBuild">
<PropertyGroup>
<LinkedProject>..\SilverlightApplication1\SilverlightApplication1.csproj</LinkedProject>
</PropertyGroup>
<MSBuild Condition="'$(LinkedProject)' != '' "
Projects="$(LinkedProject)"
Targets="Build"
Properties="CustomFlag=true" >
</MSBuild>
</Target>
The odd thing is that this works perfectly when using MSBuild from the command line, yet does not work in Visual Studio when building the web project. I thought this might be some sort of Silverlight problem, and had the task build a .NET class library project instead, but the result was the same - it worked from the command line but not within VS. In VS there's no actual error - it's just that the Csc task does not compile the assembly and generates no output.
What do I need to do to get this working within Visual Studio?
Pass the 'UseHostCompilerIfAvailable=false' property to the MSBuild task.
It looks like Visual Studio breaks badly if csc is invoked from a MSBuild task as it reuses the initial project build settings for its in-process host compiler. In my case, I was building the same project twice - default build was using target framework v3.5, with a AfterBuild MSBuild task specifying v4.0. I ended up with the same issue - csc appeared to run but produced no output. I think what was happening was that with the UseHostCompilerIfAvailable property set to true, csc was calling the hosted compiler which reused my initial project settings, so even though the command line showed csc "building" my v4.0 assembly, the host compiler was simply overwriting the v3.5 one I had just built!
Change Visual Studio verbosity to detailed and check build log. I think that CoreBuild is not executed if your files have not changed, so you could try to use AfterCompile instead of AfterBuild.

Visual Studio post build command running before SharePoint package is created

I'm updating some VS SharePoint projects so when they are built, both dll's and wsp's (packages) are created.
I found this page describing the process, but issue is that, while my project file looks like this:
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\SharePointTools\Microsoft.VisualStudio.SharePoint.targets" />
<PropertyGroup>
<BuildDependsOn>$(BuildDependsOn);CreatePackage</BuildDependsOn>
</PropertyGroup>
<PropertyGroup>
<PostBuildEvent>"$(SolutionDir)PostBuild.cmd" "$(SolutionDir)" "$(TargetDir)"</PostBuildEvent>
</PropertyGroup>
PostBuild.cmd is run BEFORE packaging happens, so when starting clean, this is the output:
------ Rebuild All started: Project: Sample, Configuration: Debug Any CPU ------
SampleProject -> C:\Inter\bin\Debug\Sample.dll
C:\Inter\bin\Debug\Sample.dll
1 File(s) copied
File not found - *.wsp
0 File(s) copied
Successfully created package at: C:\Inter\Sample\bin\Debug\Sample.wsp
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========
Any ideas? Thanks!!!
Solution can be found here.
Visual Studio & SharePoint: how to create package as part of the build
process In order to build a project and have the package created, this
can be added to the project file (csproj, vbproj):
<PostBuildEventDependsOn>
$(PostBuildEventDependsOn);
CreatePackage;
</PostBuildEventDependsOn>
That's right. PostBuild event occurs after buiding assembly.

Resources