Visual Studio WiX installer project deleting msi output on Rebuild - visual-studio-2010

I have inherited a WiX project from a contractor that recently left.
When I build the WiX installer project, there is no problem - the .msi is built and output as expected.
But when I "rebuild" the WiX installer project, again the .msi is built just fine by light.exe, but it subsequently gets deleted by a "CoreClean".
Further info: The wix project packages (and references) a single web project.
This is a snippet of the output:
ICE105: ICE105 - Validates the package to make sure that it can be installed in true Per-User mode
ICE105: Created 05/01/2008. Last Modified 05/21/2008.
Laying out media.
Moving file 'C:\Users\codemonkey\AppData\Local\Temp\nxkfdvui\AmazonWebsiteInstaller.msi' to 'C:\web\main\Amazon.Webby.Install\bin\Release\AmazonWebsiteInstaller.msi'.
Done executing task "Light".
...
...
Target "CoreClean" in file "C:\Program Files (x86)\MSBuild\Microsoft\WiX\v3.x\wix2010.targets" from project "C:\web\main\Amazon.Webby.Install\Amazon.Webby.Install.wixproj" (target "Clean" depends on it):
Task "ReadLinesFromFile"
Done executing task "ReadLinesFromFile".
Task "FindUnderPath"
Comparison path is "bin\Release\".
Done executing task "FindUnderPath".
Task "FindUnderPath"
Comparison path is "obj\Release\".
Done executing task "FindUnderPath".
Task "Delete"
Deleting file "C:\web\main\Amazon.Webby.Install\bin\Release\AmazonWebsiteInstaller.msi".
Deleting file "C:\web\main\Amazon.Webby.Install\bin\Release\AmazonWebsiteInstaller.wixpdb".
Deleting file "obj\Release\MainWixComponents.wixobj".
Deleting file "obj\Release\UploadContent.wixobj".
Deleting file "obj\Release\WebSiteContent.wixobj".
Deleting file "obj\Release\Product.Generated.wixobj".
Done executing task "Delete".
...
...
I can't find any delete task in the installer project file that involve the msi or output folder, so it's a result of visual studio doing a rebuild and thinking it needs to clean out files that it doesn't.
This seems to be the relevant section in "C:\Program Files (x86)\MSBuild\Microsoft\WiX\v3.x\wix2010.targets" causing the delete of the newly built msi:
<!--
==================================================================================================
CoreClean
Cleans all of the compile and link outputs as well as any intermediate files generated along
the way.
==================================================================================================
-->
<PropertyGroup>
<CoreCleanDependsOn></CoreCleanDependsOn>
</PropertyGroup>
<Target
Name="CoreClean"
DependsOnTargets="$(CoreCleanDependsOn)">
...
<!-- Delete those files. -->
<Delete Files="#(_CleanPriorFileWritesInOutput);#(_CleanPriorFileWritesInIntermediate)" TreatErrorsAsWarnings="true">
<Output TaskParameter="DeletedFiles" ItemName="_CleanPriorFileWritesDeleted" />
</Delete>
...
Any ideas?
Thanks.

I know it's old but this is mentioned as a fixed bug in SourceForge:
http://sourceforge.net/tracker/?func=detail&atid=642714&aid=1719357&group_id=105970
Are you using a version post 3.0.4102.0?
There does seem to be some debate as to whether the bug is really fixed in the comments.

To resolve this I took all the InitialTargets steps (which were msbuild.exe calls) out of the wixproj file and moved them into a batch script called from the pre-build event project property. I did this because there was another problem - the targeted projects were being built as the project was loaded, which meant that it took a long time to open the solution. At any rate, moving everything into a batch file resolved both problems.

Related

devenv copies files from other project during incremental build

I have 3 projects; Project1.Web, Project1.Service and Project1.Common.
Both Project1.Web and Project1.Service have dependencies on Project1.Common.
If I rebuild the solution which contains all 3 projects; all works correctly.
If I change a file in Project1.Web; files are built to Project1.Web\bin - all works correctly.
If if change a file in Project1.Service files are built to Project1.Service\bin\Debug AND some are copied to Project1.Web\bin. The copied file is Project1.Common.dll, but Project1.Web.dll is not built (or copied).
The file modified in Project1.Service is not shared, its just modified to trigger an incremental build of Project1.Service.
Does anyone know why Visual Studio would be copying a build artifact to a a directory that is not part of the incremental build?
Currently this sequence of events leaves Project1.Web is a non-working state as Project1.Service and Project1.Web have dependencies on different versions of the same assembly via a third party assembly. If we decide to make a change to Project1.Service then it has the side-effect of breaking Project1.Web.
I've tried/checked the following:
There are no dependencies between Project1.Web and Project1.Service (either direction).
The file modified in Project1.Service is not shared; and there are no pre/post build events defined.
Executing msbuild on the Project1.Service.csproj project file does not have the same effect.
Denying write/create permission on the bin directory under Project1.Web does not cause the incremental build to fail.
No output is emitted in the detailed or diagnostic msbuild output that references Project1.Web (from within Visual Studio)
Using procmon, I can see that devenv is using mswebprj.dll (C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Packages\mswebprj.dll) - which invokes the copy of the file.

SlowCheetah executes after post-build events

I use SlowCheetah to transform my app.configs. I have a multi-project solution where one of the projects executes a post-build event where the output of the bin is copied elsewhere. I've found that SlowCheetah does it's transforms after the post-build event, so the app.config I'm copying is the pre-transformed version.
Does anyone have a suggestion of how I can execute my copy after the SlowCheetah transforms? Is this going to require that I write a custom build task?
If you are using msbuild 4.0 for building your projects - you can hook to slowcheetah targets with new AfterTargets BeforeTargets attributes.
I dont know what exactly target name you want to hook after but this code could gave you base concept how to do this
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Some_Target_Name" AfterTargets="TransformAllFiles" >
<Message Text="= Script here will run after SlowCheetah TransformAllFiles ="/>
</Target>
<Project>
Edited: I installed SlowCheetah and found that AfterTargets attribute should be "TransformAllFiles".
Just set up your target dependency AfterTargets="TransformAllFiles"
Alexey's answer leads to the correct solution but here it is in full:
Right-click your project and select Unload Project
Now right-click the project and select Edit [your project name].csproj
Scroll to the bottom and uncomment the target named AfterBuild and add this attribute AfterTargets="TransformAllFiles"
Move your post build actions into this target using the Exec command:
An example:
<Target Name="AfterBuild" AfterTargets="TransformAllFiles">
<Exec Command="ECHO Hello PostBuild World!" />
</Target>
I have bumped into this problem too... decided to update to latest version of SlowCheetah (current 2.5.8), and this problem appears to have been fixed! No more problems using post-build events to deploy a project with transformed XML!
After the NuGet package upgrade process, I had a strange issue, though... transforms were no longer happening. Editing the project like Naeem Sarfraz suggested, I have found that the SlowCheetah's PropertyGroup section was placed at the end of the .csproj.
It was just a matter of moving it to the top, near the other PropertyGroup sections, and now it works like a charm!
If you need to copy/move other .config files (other than web.config) around after the build before publishing here is how it can be done with Visual Studio 2013 (I didn't test it on earlier versions). This section can be added at the end of the .csproj file right before the closing tag </Project> and it'll be fired just before MSDeploy starts the Publishing process.
<Target Name="MoveConfigFile" BeforeTargets="MSDeployPublish">
<Move
SourceFiles="$(IntermediateOutputPath)Package\PackageTmp\ThirdPartyApp.config"
DestinationFolder="$(IntermediateOutputPath)Package\PackageTmp\bin"
OverwriteReadOnlyFiles="true"
/>
</Target>
The company I work for purchased a third party product that needs to have a .config files in the bin folder along with its assembly in order to work.
At the same time we need to process the product's .config file and be able to move it to the bin folder after transformations.
The $(IntermediateOutputPath)Package\PackageTmp folder contains the whole application that will be copied over the target server.

Executable not rebuilt but object files recompiled

Building a basic C++ project with Visual Studio 2012. When I make changes to source files:
the corresponding object files are compiled
the .tlog files for the compiler are updated
the PDB file is updated
the .tlog files for the linker however are not changed
the linker claims All outputs are up-to-date. and does not build a new executable.
The only way to get the executable to be built is deleting it. It seems something with the tracking system is wrong and I was wondering if anyone can shed some light on this issue.
Here is the msbuild output after I change two files, full paths and some other stuff omitted (this output is for the VS2010 toolset, but 2012 behaves the same):
1>Target "ClCompile" in file "C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\Microsoft.Cpp.Win32.targets"...
Using "CL" task from assembly "Microsoft.Build.CppTasks.Win32, Version=4.0.0.0...
Task "CL"
Read Tracking Logs:
cl.read.1.tlog
CL.2520.read.1.tlog
...
Outputs for ....
XXX.OBJ
YYY.OBJ
...
xxx.cpp will be compiled as xxx.cpp was modified...
yyy.cpp will be compiled as yyy.cpp was modified...
Write Tracking Logs:
cl.write.1.tlog
CL.2520.write.1.tlog
...
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\CL.exe ....
Tracking command:
C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\Tracker.exe ....
xxx.cpp
yyy.cpp
Done executing task "CL".
1>Done building target "ClCompile" in project "xxx.vcxproj".
so far, so good. Now the linker kicks in (well, it doesn't):
1>Target "Link" in file "C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\Microsoft.Cpp.Win32.targets"....
Using "Link" task from assembly "Microsoft.Build.CppTasks.Win32, Version=4.0.0.0...
Task "Link"
Using cached output dependency table built from:
link.write.1.tlog
Using cached input dependency table built from:
ink.read.1.tlog
Outputs for ....
MY.EXE
MY.PDB
All outputs are up-to-date.
Done executing task "Link".
Task "Message"
xxx.vcxproj -> my.exe
Done executing task "Message".
1>Done building target "Link" in project "xxx.vcxproj".
After checking all options we have in the property sheets one-by-one, it seems the sole source of this problem is that we have the intermediate directory set to a directory on another drive. We always do out of source builds in %TEMP%, and most of the time the projects reside on another drive.
Filed a bug report here including simple steps that reproduce the problem. Hopefully this gets fixed soon. Current soltuion is to set IntDir to a direcyory on the same drive as the project.
UPDATE
The bug report filed for this issue was closed as 'by design': it seems the Intermediate Directory should not be %TEMP% or %TMP% or any subdirectory of those. Disturbing, but at least I know what was wrong now.

What is incremental clean in msbuild and when is it triggered?

I am debugging a bug in my build process that happens occasionally but I can't directly reproduce it. I'm using msbuild with teamcity.
I have a dependency hierarchy like this:
Some.Interop.dll
Dependency-> SharedDllABC.dll
SomeService.exe
Depenendcy-> Some.Interop
Usually the final service exectuable gets in its release directory:
Some.Interop
SharedDllABC.Dll
ServiceExectuable.exe
However I can see in our msbuild logs that sometimes the tertiary dependency gets deleted during an Incremental Clean after everything is built resulting in:
Some.Interop
ServiceExectuable.exe
You can see it here in the msbuild log:
[src\SomeService\SomeService.csproj] _TimeStampAfterCompile
[12:32:43]: [src\SomeService\SomeService.csproj] Compile
// some other targets
[12:32:43]: [src\SomeService\SomeService.csproj] _CopyFilesMarkedCopyLocal
[12:32:43]: [_CopyFilesMarkedCopyLocal] Copy
[12:32:43]: [Copy] Copying file from "C:Projects\trunk\src\Some.Interop\bin\Release\Some.Interop.dll" to "bin\Release\Some.Interop.dll".
// some other targets
[src\Project\SomeService\SomeService.csproj] IncrementalClean
[18:54:42]: [IncrementalClean] Delete
[18:54:42]: [Delete] Deleting file "C:\Projects\trunk\src\Project\SomeService\bin\Release\SharedDllABC.dll".
[18:54:42]: [Delete] Deleting file "C:\Projects\trunk\src\Project\SomeServiceService\bin\Release\SharedDllABC.pdb".
[18:54:42]: [src\Project\SomeService\SomeService.csproj] CoreBuild
[18:54:42]: [src\Project\SomeService\SomeService.csproj] AfterBuild
[18:54:42]: [src\Project\SomeService\SomeService.csproj] Build
This is my direct msbuild output, I just changed the project names/dll names to match my example. By the time this Incremental Clean has occurred the SomeService.csproj has already been built. You can see that its not getting copied. However in other msbuild logs it does properly get copied and then the incremental clean doesn't delete it.
I think incrementeal clean from this post is supposed to clean dll's that were created from previous builds, but that doesn't explain how this dll didn't get built when most of the time it does. In visual studio this always works as well.
I guess I just want to know what exactly is Incremental clean, what causes it to kick in, and maybe what things I should look for when debugging a situation like this (assembly versions, timestamps, etc?)
Try the following:
Add:
<Target Name="IncrementalClean" />
to a .targets file that's included in all projects.
From --> https://github.com/Microsoft/msbuild/issues/1054
#Kebabbi recommends a good fix by editing a csproj file. As of MSBuild 15, there is a simple way to make this apply to all CSPROJ files, instead of editing each csproj file.
https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2017
Directory.Build.props and Directory.Build.targets
Prior to MSBuild version 15, if you wanted to provide a new, custom property to projects in your solution, you had to manually add a reference to that property to every project file in the solution. Or, you had to define the property in a .props file and then explicitly import the .props file in every project in the solution, among other things.
However, now you can add a new property to every project in one step by defining it in a single file called Directory.Build.props in the root folder that contains your source. When MSBuild runs, Microsoft.Common.props searches your directory structure for the Directory.Build.props file (and Microsoft.Common.targets looks for Directory.Build.targets). If it finds one, it imports the property. Directory.Build.props is a user-defined file that provides customizations to projects under a directory.
Create a file Directory.Build.props, and place it adjacent to the SLN file.
<Project>
<Target
Name="ForceAssignProjectConfigurationBeforeSplitProjectReferencesByFileExistence_KLUDGE"
BeforeTargets="_SplitProjectReferencesByFileExistence"
DependsOnTargets="AssignProjectConfiguration" />
</Project>
This could be caused by a bug in MsBuild: https://github.com/Microsoft/msbuild/issues/1054.
A fix is proposed in the comments: https://github.com/Microsoft/msbuild/issues/1054#issuecomment-406438561
When MsBuild determines which items to copy from referenced projects, it should do this recursively but does not properly do this.
As a workaround the following can be added to each csproj.
<Target
Name="ForceAssignProjectConfigurationBeforeSplitProjectReferencesByFileExistence_KLUDGE"
BeforeTargets="_SplitProjectReferencesByFileExistence"
DependsOnTargets="AssignProjectConfiguration"
/>
I just spent a few days trying to figure this out with a similar pattern. In our case it was nuget files that were being removed from the output folder.
NugetPackage (that drops files in x86/x64 subfolders in output folder)
LibraryA.dll
Dependency-> NugetPackage
LibraryB.dll
Dependency-> LibraryA.dll
In our case, we have a number of solution files that are built as part of an msbuild script in a certain order.
The problem was that LibraryB.csproj was included in two solution files.
Solution1 builds and output files are all present.
Solution2 builds and sees that LibraryB.dll is present and up to date, so for some reason triggers the IncrementalClean that removes the NugetPackage files from the output folder.
Once I removed the LibraryB.csproj from solution 2, the problem is solved and the files are present in the output folder.

Anyone else notice that $(SolutionDir) resolves to ProjectDir when loading Wix projects into Vs2010?

I'm using Vs2010 and Wix 3.6.0917.0, for the record. I use the $(SolutionDir) property quite a bit in my .wixproj file, since I only ever build the installer as part of a solution build or as part of a team build, and never by itself. However, while building from the command line works just fine (both from cmd on the desktop and when building on build agents), when I attempt to reload the .wixproj file into the IDE, I get errors because all the $(SolutionDir) variables are resolving to the project directory, not the solution directory. Consider:
C:\workspace\projectCollection\teamProject\branch\solution.sln
C:\workspace\projectCollection\teamProject\branch\source\installer\installer.wixproj
and assume a shared custom targets file:
C:\workspace\projectCollection\teamProject\branch\build\shared.targets
which is referenced inside installer.wixproj with:
<Import Project="$(SolutionDir)build\shared.targets">
Command line builds work fine...
C:\workspace\projectCollection\teamProject\branch\> MSBuild /t:build /property:Platform=x64;Configuration=Debug solution.sln
0 Errors
0 Warnings
Build succeeded!
But load into vs2010 and you see...
The imported project
"C:\workspace\projectCollection\teamProject\branch\source\installer\build\shared.targets" was not found.
Confirm that the path in the <Import> declaration is correct, and that the file exists on disk.
C:\workspace\projectCollection\teamProject\branch\source\installer\installer.wixproj
You can see here that the resolved result of $(SolutionDir)build\shared.targets is getting the project directory and not the solution directory. What gives?
My guess would be that $(SolutionDir) resolves to nothing when the wixproj is being loaded into VS2010. In this case the imported file becomes "build\shared.targets". Since the path is relative it is assumed to be relative to the project directory. Using ".." or some other path could get you around the problem.
I verified this failed with WiX 3.5.2222.0 in VS2010. A C# console application project (csproj) worked as expected.
Have you filed a bug against WiX for this?
I looked at the WiX vs2010 addin code a little bit and the Solution properties are only created when doing a build and not when the project is loaded.

Resources