Wix Build Order - msbuild & Heat - msbuild

I am trying to extend our existing Wix Project with Heat to include all files from the output directory of another project in the installer. Somehow I`m missing something that should be very easy since I guess this is a very common task.
Here is what the solution looks like:
SomeDependencyA.csproj
SomeDependencyB.csproj (Depends on SomeDependencyA)
WindowsService.csproj (Depends on SomeDependencyB)
Installer.wixproj(Depends on WindowsService.csproj)
Wix should basically grep anything from WindowsService Output folder and build the msi package from it. The process should be:
Build all Dependencies
Build WindowsService project
Generate a Fragement using Heat
Build the Installer
And here is my question: Where/how do I have to include the call to Heat? Pre-Build Step and BeforeBuild Target does not work, since at this time the WindowsService and the Dependencies are not Build yet. AfterBuild wouldn´t help, since at that point the generated Fragment would not be cosidered anymore. I was looking for some build target that is calles AFTER all dependencies have been build but BEFORE the Installer Project itself has been build. Should be easy, but I couldn´t figure it out yet.

The BeforeBuild target will happen potentially before a dependant project has completed its build.
A solution I've used for this type of build ordering in the past is to add a DependsOnTargets for the BeforeBuild target;
For csproj:
<Target Name="BeforeBuild" DependsOnTargets="ResolveReferences">
For vcxproj:
<Target Name="BeforeBuild" BeforeTargets="PrepareForBuild">
This will force the project to wait until the dependant projects are completed before running the BeforeBuild target.

Related

MSBuild: ProjectReference Output Path in Wix Projects

I'm trying to get the Output folder of referenced project in my Wix Visual Studio project, using MsBuild task. But it is failing with following error:
C:\Program Files
(x86)\MSBuild\14.0\bin\Microsoft.Common.CurrentVersion.targets(724,5):
error : The OutputPath property is not set for project
'ConsoleApplicatio n1.csproj'. Please check to make sure that you
have specified a valid combination of Configuration and Platform for
this project. Configuration='Release' Platfo rm='x86'. You may be
seeing this message because you are trying to build a project without
a solution file, and have specified a non-default Configuration or
Plat form that doesn't exist for this project.
[C:\Users\fwaheed\Documents\Visual Studio
2015\Projects\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.cspro
j]
Following is the Target calling MsBuild task.
<Target Name="AfterBuild">
<MSBuild
Projects="#(ProjectReference)"
Targets="GetTargetPath"
BuildInParallel="false"
Condition="'%(Name)'=='ConsoleApplication1'" >
<Output TaskParameter="TargetOutputs" ItemName="DependentAssemblies" />
</MSBuild>
</Target>
Please note that same target worked perfectly if it is CSharp project, but failing in Wix project.
Can someone guide how to get ReferencedProjects output dirs in Wix Projects?
Thanks
You can try to see how Wix does it for passing the reference values to candle on build. They're in the wix2010.targets or wix200x.targets file. Unfortunately I don't have the time to really dig into this stuff but the properties these tasks set should still exist to be used in your AfterBuild target.
Just search for "ResolveReferences" in one of those targets files.
You can also just try setting
<OutputPath>somepathhere</OutputPath>
in your csproj file since msbuild is complaining that the property isn't set.

WiX Heat: Pre-build event fires too early on build server

I'm harvesting a directory for my Visual Studio solution.
It works on my local system so far probably because the project build order is being respected.
When I run the installer on a build server it finds the right directory but it has not been created at the time of building the setup file. It throws a HEAT5052 error saying The directory 'a:\b\c' could not be found.
Is there any way to "wait" until or to execute the heat command after all project references are built?
OK so I've spent hours to figure out how to fire Heat AFTER all references are resloved. I only found solutions for the <PreBuildEvent> and <PostBuildEvent> using the Heat command line and the BeforeBuild and AfterBuild targets.
So I found all kind of targets inside the wix2010.targets file located in my
Program files (x86)\MSBuild\Microsoft\Wix\ folder. It contains a target called AfterResolveReferences and it does exactly that. So here's my code I ended up with (in case someone is interested):
<Target Name="AfterResolveReferences">
<HeatDirectory
ToolPath="$(WixToolPath)"
OutputFile="Product.Binaries.wxs"
SuppressFragments="$(HarvestDirectorySuppressFragments)"
Transforms="Filter.xslt"
Directory="$(HarvestFolder)"
DirectoryRefId="MY_FOLDER"
ComponentGroupName="Binaries"
GenerateGuidsNow="true"
SuppressRootDirectory="true"
SuppressRegistry="true"
PreprocessorVariable="var.App.TargetDir">
</HeatDirectory>
</Target>
I had the same problem and it was solved by combining the accepted answer and this answer to ensure that my post build event, which was copying files, always runs:
<RunPostBuildEvent>Always</RunPostBuildEvent>
<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
Also, my build server was using the MSBuild command line, and I used this answer to locate my local MSBuild.exe so I could test my changes locally without having to push to the build server.

MSBUILD - block until a file exists on an ftp server?

As part of a build process .. I would like to block the build until a file gets created (exists) remotely at an ftp location, after which I would continue the build. (Preferably with somekind of time out limit).
Suggestions?
Is this even possible using only the standard msbuild task and/or extensionPack/communitytask?
Your best bet is to build a small custom exe (you can even compile it as a build step) that polls for the file you are looking for. Then you use the PreBuild target, or a custom target in a pre-build step to verify that the file exists.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="WaitOnFTP">
<Exec Command="MyFTPWaiter.exe"/>
</Target>
</Project>
Other more MSBuild oriented suggestions are to remake that exe as a custom task, or even an inline task in MSBuild 4.0.
FWIW, I've encountered a similar solution done by a peer who didn't want large binaries used by integration tests in version control and he required the use of a custom downloader in the build to get the files from a SMB share. It worked well enough.
Custom Tasks
Inline Tasks

How to aggregate outputs from a dynamically generated set of projects into a single folder

I need to collect into a single folder all test assemblies, with their dependencies, and configuration files. The process should preserve the directory structure from the output of each test project. We have a solution that requires manually attaching test projects to a master project, but our solution has far too many projects for this to be maintainable. These should be located automatically based on naming convention (x.UnitTest.csproj, y.IntegrationTest.csproj).
For background, we are working with a build system that passes artifacts (binaries, etc) between agents. We are compiling on one agent, and testing on other agents. The massive duplication of assemblies between test projects is slowing the build process down.
What I have done:
1) I have a csproj that references most of the test projects. This gets binaries and dependencies into one folder.
2) I am able to identify all files to copy using this
<CreateItem
Include="%(ProjectReference.RootDir)%(ProjectReference.Directory)$(OutDir)*.config">
<Output TaskParameter="Include" ItemName="TestConfigurationFiles"/>
</CreateItem>
<Copy
SourceFiles="#(TestConfigurationFiles)"
DestinationFolder="$(OutDir)">
</Copy>
I've attempted most obvious things, such as
MsBuild task: RebaseOutputs attribute, overriding the OutDir property. I can provide the msbuild task with a dynamically generated set of outputs, but can only build them in their default folder.
Hooking into the TargetOutputs of
msbuild task gives only the primary
output assembly (without
dependencies).
I experimented with "Copy Always" for
configuration files. This puts them
in the output directory of the
dependent project as "app.config" not
"dllname.config", and not in the
final project.
Solutions that could make this better might include
Provide an example of adding to the projectreference item array dynamically, before compilation.
Use msbuild TargetOutputs to create a list of all files in the folder (instead of just the primary output) and copy to a destination folder.
Today I'm using msbuild 3.5. Ideally the solution would work with msbuild 3.5. We are transitioning to .NET 4 / MsBuild 4 soon, so, if must be done in .Net 4, that is fine.
Have you considered flattening the folder structure when you export your artifacts?
Something like:
src/*.UnitTest*/bin/**/*.* -> /testlibs
src/*.IntegrationTest*/bin/**/*.* -> /testlibs

MSBuild speedup: how to remove unnecessary project builds?

I have a solution with several projects in it. Let's say
project A depends on projects B and C
project B depends on project C
When I run my solution on the local machine VS builds each project once and it takes 1 minute. However, on our build machine it takes about 4 minutes to build and, as I can understand from the MSBuild logs it goes like this:
build A -> build B for A, build C for A
build B -> build C for B
So it builds some projects several times... How can I speed up the build process?
P.S. It's not a question of 3 extra minutes, I just wonder why is it so different from my local machine build?
I am not sure about your build order. Sometimes TeamBuild can look like it is building projects over and over but it is building for different configurations. Take a look and make sure you have not defined multiple FlavorsToBuild.
Also, if you don't want to do a fresh check out and rebuild every time, you can define this at the bottom of your TFSBuild file.
<PropertyGroup>
<IncrementalBuild>true</IncrementalBuild>
</PropertyGroup>-->
Put that right before the </Project> tag.
This sample seems to work for me. TestLib.Extra depends on TestLib. If I change something in TestLib, both projects will build. If I change only in TestLib.Extra, only that one will build, and if I don't change anything at all, they will just report Skipping target "CoreCompile" because all output files are up-to-date and so on.
<Target Name="Build">
<MSBuild Targets="Build" Projects="TestLib\TestLib.csproj" />
<MSBuild Targets="Build" Projects="TestLib.Extra\TestLib.Extra.csproj" />
</Target>
The trick is to use the "Build" target of the projects, rather than "Rebuild". The difference between these is essentially the same as the difference between the "Build" and "Rebuild" commands in the build menu in Visual Studio.
Edit
This works well also if the projects are included in a solution file, and you specify the solution to build instead:
<Target Name="Build">
<MSBuild Targets="Build" Projects="TestLib.sln" />
</Target>
Maybe like our's, your build server is a virtual machine (10x at least slower).
Also TFS (and maybe others), does a fresh checkout on build, so it will have to build all the projects regardless.
Are you using the /maxcpucount switch? There may be a difference in number of processors between your local machine and the build machine. This setting can also be different between your msbuild file and the visual studio setting which could also explain the difference you're seeing in build times.
I do this as follows. It is somewhat complicated custom build system but the basic idea is.
The dlls which are reused in many solutions are build to a known folder. This is achieved my using a msbuild project file that builds these common dlls.
When building other csproj files in a solution we copy the csproj files then use xslt manipulation to replace the project references with dll refernces for those common dlls.
The build scripts then build these changed csproj files using custom msbuild project files we maintain corresponding to each solutions. We don't build .sln files. These custom project files is a itemgroup of .csproj files in correct dependency order.
Maybe this can help you in achieving what you want.