Further to my last post on sandcastle in TFS builds, I wanted to update on the complications that have happened in the last week.
Sandcastle docs and Wix installers.
Our installer, built in WiX v3, acts as a project inside the solution and builds last, rolling up the output of the other projects into an MSI file. The sandcastle action ran after this. Now we wanted to put the sandcastle .chm file into the installer, which couldn't happen as things were. The answer to this was to put the installer into its own solution, and run them in this order:
<Target Name="Build"
DependsOnTargets="GenerateBuildVersion;BuildSolutions;BuildSandcastleDocs;BuildWiXInstaller">
</Target>
Sandcastle.targets file
I'm starting to appreciate breaking down build files into smaller, single-purpose, potentially reusable chunks. We now have a file called sandcastle.targets that contains the sandcastle targets and definitions.
Release builds
The astute among you will have noticed that the contents of the Project.Documentation.shfb that I gave last time will work only for debug builds: paths such as <assembly assemblyPath="..\..\..\..\..\..\Binaries\Debug\Assembly1.dll" will get the wrong files, or be entirely missing during release builds. There is still no good way to paramaterise the .shfb file, but you can hack it a bit.
We are now doing these paths like this in the shfb file:
<assemblies>
<assembly assemblyPath="$(OutDir)Assembly1.dll " xmlCommentsPath="$(OutDir)Assembly1.XML"
commentsOnly="False" />
Then we use the MSBuild FileUpdate task to replace the text "$(OutDir)" with the contents of the variable of the same name. Before that, the Attrib task is needed to make the file writable.
Both of these are tasks are found in the MSBuild Community Tasks (http://msbuildtasks.tigris.org/)
So here's the complete sandcastle.targets file.
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<SHFBConsolePath>C:\Program Files\EWSoftware\Sandcastle Help File Builder\SandcastleBuilderConsole.exe</SHFBConsolePath>
</PropertyGroup>
<Target Name="BuildSandcastleDocs">
<!-- Build source code docs -->
<Message Text="Building projects for sandcastle: @(SandcastleProjects)" />
<!-- Update the output path -->
<Message Text="Replacing OutDir with $(OutDir)" />
<Attrib Files="@(SandcastleProjects)" ReadOnly="false"/>
<FileUpdate Files="@(SandcastleProjects)" Regex="\$\(OutDir\)" ReplacementText="$(OutDir)" />
<Exec Command=""$(SHFBConsolePath)" "@(SandcastleProjects)" -outputpath="$(OutDir)."" />
</Target>
</Project>
You may also notice that @(SandcastleProjects) is not defined in this file. This is deliberate - this file is reusable, and the value for @(SandcastleProjects) must be supplied by the caller.