Harvesting multiple directories in WiX

pheobas picture pheobas · Jun 14, 2013 · Viewed 8.6k times · Source

I'm trying to build an installer that includes a number of features and I'm using heat to harvest a directory of files for each feature.
My source directory structure looks something like this:

HarvestDir
          \FeatureA
                   \FeatureImpl.dll
                   \FeatureImpl2.dll
          \FeatureB
                   \FeatureImpl.dll
                   \FeatureImpl2.dll

So I execute heat.exe for each feature to create a fragment for each feature but I get basically identical fragments e.g.

[...] Source="SourceDir\FeatureImpl.dll"
[...] Source="SourceDir\FeatureImpl2.dll"

What I really want is something like this:

[...] Source="SourceDir\FeatureA\FeatureImpl.dll"
[...] Source="SourceDir\FeatureA\FeatureImpl2.dll"

and

[...] Source="SourceDir\FeatureB\FeatureImpl.dll"
[...] Source="SourceDir\FeatureB\FeatureImpl2.dll"

I could use -var to specify a separate variable to represent the source location for each feature, but then I'd have to pass values for these variables into the wixproj (and I'm going to have ~10 features).

So, is there any way I can include a relative path in my harvested fragment?

Answer

Tom Blodget picture Tom Blodget · Jun 17, 2013

Rather than using heat on each Feature* folder, you could just harvest the whole feature layout folder that you have created and have heat transform the results. I'm assuming that each subfolder is a feature. It's a simple matter of creating a ComponentGroup for each one that references all the components under it.

You'd then use the component groups like this:

    <Feature Id="FeatureA">
      <ComponentGroupRef Id="FeatureA"/>
    </Feature>
    <Feature Id="FeatureB">
      <ComponentGroupRef Id="FeatureB"/>
    </Feature>

Heat command (I actually use the HarvestDirectory target in WiX 3.7):

Heat.exe dir FeatureLayout -dr FeatureLayoutDir -srd -ag -sfrag -t FeatureLayout.xslt -out obj\Debug\__dir.wxs

FeatureLayout.xslt:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0"
    xmlns:wix="http://schemas.microsoft.com/wix/2006/wi"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    exclude-result-prefixes="wix"
    >

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="wix:Wix">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
      <xsl:for-each select="wix:Fragment/wix:DirectoryRef/wix:Directory">
        <wix:Fragment>
          <wix:ComponentGroup Id="{@Name}">
            <xsl:for-each select="descendant::wix:Component">
              <wix:ComponentRef Id="{@Id}"/>
            </xsl:for-each>
          </wix:ComponentGroup>
        </wix:Fragment>
      </xsl:for-each>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>