The target dir is designed for debugging on the developer machine, not for gathering files to package.
Be that as it may, you have a few options, including:
- Heat accepts an XSL transform to apply before it emits the .wxs file. With XSL, you can filter out the Component and ComponentRef elements you don't want.
- Use a project reference for Project A and Project B in WiXSetup and harvest their outputs. You'd then have to harvest xyz.dll separately or hand-write a Component for it. Manually create two Features and reference the xyz Component in both. (I'm assuming the WiXSetup is a Visual Studio project created from the WiX Setup Project template.)
- Use MSBuild's Copy task to create your package layout and harvest that. The Copy task can create hardlinks instead of actually copying. (Almost all types of Visual Studio projects are MSBuild projects.)
A simplistic XSLT for the updated question:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wix="http://schemas.microsoft.com/wix/2006/wi"
xmlns="http://schemas.microsoft.com/wix/2006/wi"
exclude-result-prefixes="wix">
<xsl:output method="xml" indent="yes"/>
<!-- Preserving the order of attributes only for aesthetic reasons -->
<xsl:template match="//wix:Component">
<xsl:variable name="source" select="wix:File/@Source" />
<xsl:variable
name="baseId"
select="concat(substring-before(substring-after($source, '$(var.'),'.TargetDir)'),
concat('.', substring-after($source,'\')))" />
<Component>
<xsl:attribute name="Id">
<xsl:value-of select="concat('cmp_', $baseId)"/>
</xsl:attribute>
<xsl:attribute name="Guid">*</xsl:attribute>
<File>
<xsl:attribute name="Id">
<xsl:value-of select="concat('fil_', $baseId)"/>
</xsl:attribute>
<xsl:attribute name="KeyPath">yes</xsl:attribute>
<xsl:attribute name="Source">
<xsl:value-of select="wix:File/@Source"/>
</xsl:attribute>
</File>
</Component>
</xsl:template>
<xsl:template match="//wix:ComponentRef">
<!-- ComponentRef nodes are interleaved with text() nodes. Want positions 2, 4, 6, ... -->
<xsl:variable name="index" select="(position() - 1) div 2" />
<xsl:variable name="source" select="//wix:Component[$index]/wix:File/@Source" />
<xsl:variable
name="baseId"
select="concat(substring-before(substring-after($source, '$(var.'),'.TargetDir)'),
concat('.', substring-after($source,'\')))" />
<ComponentRef>
<xsl:attribute name="Id">
<xsl:value-of select="concat('cmp_', $baseId)"/>
</xsl:attribute>
</ComponentRef>
</xsl:template>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>