Using Sandcastle August CTP and MSBuild to produce CHM documentation automatically
First, we created a cmd file to do the build for us. Syntax for calling the file is Build.cmd "PathToBinaries" "Name of the documentation" (more on this later)
@echo off
PUSHD %1
"%programfiles%\Sandcastle\ProductionTools\mrefbuilder.exe" *.dll /out:%~dp0\reflection.org /dep:%windir%\Microsoft.NET\Framework\v2.0.50727\*.dll,C:\deps\*.dll,%WINDIR%\assembly\GAC_MSIL\Microsoft.VisualStudio.QualityTools.UnitTestFramework\8.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll
IF ERRORLEVEL 1 EXIT /B 1
POPD
"%programFiles%\Sandcastle\ProductionTools\XslTransform.exe" /xsl:"%programfiles%\Sandcastle\ProductionTransforms\AddOverloads.xsl" /xsl:"%programfiles%\Sandcastle\ProductionTransforms\AddGuidFilenames.xsl" reflection.org /out:reflection.xml
IF ERRORLEVEL 1 EXIT /B 1
"%programFiles%\Sandcastle\ProductionTools\XslTransform.exe" /xsl:"%programfiles%\Sandcastle\ProductionTransforms\ReflectionToManifest.xsl" reflection.xml /out:manifest.xml
IF ERRORLEVEL 1 EXIT /B 1
if not exist Output mkdir Output
if not exist Output\html mkdir Output\html
if not exist Output\art mkdir Output\art
if not exist Output\scripts mkdir Output\scripts
if not exist Output\styles mkdir Output\styles
copy "%programfiles%\Sandcastle\Presentation\art\*" Output\art > NUL
copy "%programfiles%\Sandcastle\Presentation\scripts\*" Output\scripts > NUL
copy "%programfiles%\Sandcastle\Presentation\styles\*" Output\styles > NUL
"%programfiles%\Sandcastle\ProductionTools\BuildAssembler.exe" /config:sandcastle.config manifest.xml
IF ERRORLEVEL 1 EXIT /B 1
"%programFiles%\Sandcastle\ProductionTools\XslTransform.exe" /xsl:"%programfiles%\Sandcastle\ProductionTransforms\ReflectionToChmProject.xsl" reflection.xml /out:Output\%2.hhp
IF ERRORLEVEL 1 EXIT /B 1
"%programFiles%\Sandcastle\ProductionTools\XslTransform.exe" /xsl:"%programfiles%\Sandcastle\ProductionTransforms\ReflectionToChmContents.xsl" reflection.xml /arg:html=Output\html /out:Output\%2.hhc
IF ERRORLEVEL 1 EXIT /B 1
"%programFiles%\Sandcastle\ProductionTools\XslTransform.exe" /xsl:"%programfiles%\Sandcastle\ProductionTransforms\ReflectionToChmIndex.xsl" reflection.xml /out:Output\%2.hhk
IF ERRORLEVEL 1 EXIT /B 1
CD OUTPUT
"%programfiles%\HTML Help Workshop\hhc.exe" %2.hhp
CD ..
There is also a configuration file we're using referenced in our call to BuildAssembler.exe; here is that
<configuration>
<dduetools>
<builder>
<components>
<!-- Create skeleton document -->
<component type="Microsoft.Ddue.Tools.CopyFromFileComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">
<data file="%programfiles%\Sandcastle\Presentation\transforms\skeleton.xml" />
<copy source="/*" target="/" />
</component>
<!-- Copy in reflection data -->
<component type="Microsoft.Ddue.Tools.CopyFromIndexComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">
<index name="reflection" value="/reflection/apis/api" key="@id" cache="10">
<data files="reflection.xml" />
</index>
<copy name="reflection" source="*" target="/document/reference" />
</component>
<!-- Copy in container data -->
<component type="Microsoft.Ddue.Tools.CopyFromIndexComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">
<copy name="reflection" key="string(/document/reference/containers/container/@namespace)" source="*[not(local-name()='elements')]" target="/document/reference/containers/container[@namespace]" />
</component>
<component type="Microsoft.Ddue.Tools.CopyFromIndexComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">
<copy name="reflection" key="string(/document/reference/containers/container/@type)" source="*[not(local-name()='elements')]" target="/document/reference/containers/container[@type]" />
</component>
<!-- Generate syntax -->
<component type="Microsoft.Ddue.Tools.IfThenComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">
<if condition="not(starts-with($key,'Overload:') or starts-with($key,'R:'))" />
<then>
<component type="Microsoft.Ddue.Tools.SyntaxComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">
<syntax input="/document/reference" output="/document/syntax" />
<generators>
<generator type="Microsoft.Ddue.Tools.CSharpDeclarationSyntaxGenerator" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\SyntaxGenerators.dll" />
<generator type="Microsoft.Ddue.Tools.VisualBasicDeclarationSyntaxGenerator" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\SyntaxGenerators.dll" />
<generator type="Microsoft.Ddue.Tools.CPlusPlusDeclarationSyntaxGenerator" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\SyntaxGenerators.dll" />
</generators>
</component>
</then>
</component>
<!-- Copy in comments -->
<component type="Microsoft.Ddue.Tools.CopyFromIndexComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">
<index name="comments" value="/doc/members/member" key="@name" cache="100">
<data files="Documentation\*.xml" />
</index>
<copy name="comments" source="*" target="/document/comments" />
</component>
<!-- Copy in reflection data and comments for members -->
<component type="Microsoft.Ddue.Tools.ForEachComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">
<variable expression="/document/reference/elements/element/@api" />
<components>
<component type="Microsoft.Ddue.Tools.CopyFromIndexComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">
<copy name="reflection" source="*[not(local-name()='elements')]" target="/document/reference/elements/element[@api=$key]" />
</component>
<component type="Microsoft.Ddue.Tools.CopyFromIndexComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">
<copy name="comments" source="summary" target="/document/reference/elements/element[@api=$key]" />
</component>
</components>
</component>
<!-- transform -->
<component type="Microsoft.Ddue.Tools.TransformComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">
<transform file="%programfiles%\Sandcastle\Presentation\transforms\main_sandcastle.xsl" />
</component>
<!-- resolve shared content -->
<component type="Microsoft.Ddue.Tools.SharedContentComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">
<content file="%programfiles%\Sandcastle\Presentation\content\shared_content.xml" />
<content file="%programfiles%\Sandcastle\Presentation\content\reference_content.xml" />
</component>
<!-- resolve reference links -->
<component type="Microsoft.Ddue.Tools.ResolveReferenceLinksComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">
<targets files="reflection.xml" type="local" />
</component>
<!-- save the result -->
<component type="Microsoft.Ddue.Tools.SaveComponent" assembly="%programfiles%\Sandcastle\ProductionTools\BuildComponents\BuildComponents.dll">
<save path="concat('Output\html\',/html/head/meta[@name='guid']/@content,'.htm')" indent="false" omit-xml-declaration="true" />
</component>
</components>
</builder>
</dduetools>
</configuration>
Now we have to hook it up to MSBuild. Within the TFSProj.proj file, a new target was created called by an override to the Team Build AfterDrop target
<PropertyGroup>
<SandcastleDocumentDirectory>$(TEMP)\SandcastleDocument</SandcastleDocumentDirectory>
</PropertyGroup>
<Target Name="SandcastleDocument">
<CreateProperty Value="MyDocumentation">
<Output TaskParameter="Value" PropertyName="SandcastleDocumentationName"/>
</CreateProperty>
<RemoveDir Condition="Exists('$(SandcastleDocumentDirectory)')" Directories="$(SandcastleDocumentDirectory)" ContinueOnError="false"/>
<MakeDir Directories="$(SandcastleDocumentDirectory)" ContinueOnError="false" />
<CreateItem Include="$(SolutionRoot)\Sandcastle\Aug 2006 CTP\Build.cmd">
<Output ItemName="SandcastleBuildScript" TaskParameter="Include"/>
</CreateItem>
<Copy SourceFiles="@(SandcastleBuildScript)" DestinationFiles="@(SandcastleBuildScript -> '$(SandcastleDocumentDirectory)\Build.cmd')" ContinueOnError="false" />
<CreateItem Include="$(SolutionRoot)\Sandcastle\Aug 2006 CTP\sandcastle.config">
<Output ItemName="SandcastleConfiguration" TaskParameter="Include"/>
</CreateItem>
<Copy SourceFiles="@(SandcastleConfiguration)" DestinationFiles="@(SandcastleConfiguration -> '$(SandcastleDocumentDirectory)\sandcastle.config')" ContinueOnError="false" />
<MakeDir Directories="$(SandcastleDocumentDirectory)\Documentation" ContinueOnError="false"/>
<CreateItem Include="$(BinariesRoot)\x86\Debug\*.xml">
<Output ItemName="CodeDocumentationFiles" TaskParameter="Include"/>
</CreateItem>
<Copy SourceFiles="@(CodeDocumentationFiles)" DestinationFiles="@(CodeDocumentationFiles -> '$(SandcastleDocumentDirectory)\Documentation\%(Filename)%(Extension)')" ContinueOnError="false"/>
<Exec WorkingDirectory="$(SandcastleDocumentDirectory)" Command="Build.cmd "$(BinariesRoot)\x86\Debug" $(SandcastleDocumentationName)" ContinueOnError="false" />
<CreateItem Include="$(SandcastleDocumentDirectory)\output\$(SandcastleDocumentationName).chm" ContinueOnError="false">
<Output ItemName="SandcastleDocumentationFiles" TaskParameter="Include"/>
</CreateItem>
<MakeDir Condition="!Exists('$(BinariesRoot)\Documentation')" Directories="$(BinariesRoot)\Documentation" ContinueOnError="false" />
<Copy SourceFiles="@(SandcastleDocumentationFiles)" DestinationFiles="@(SandcastleDocumentationFiles -> '$(BinariesRoot)\Documentation\%(RecursiveDir)%(Filename)%(Extension)')" ContinueOnError="false" />
<OnError ExecuteTargets="OnBuildBreak;"/>
</Target>
Comments
- Anonymous
October 02, 2006
The comment has been removed