Wix/Heat:访问 .wixproj 文件中的 <ProjectReference>

Wix/Heat: Access <ProjectReference> inside .wixproj file

我是 运行 在我的 installer.wixproj 中作为预构建事件的热命令。 我希望我的 dir 参数 (HarvestPath) 成为我包含的项目引用的目标目录。

现在我的 .wixproj 文件中有

<PropertyGroup>
  <HarvestPath Condition=" '$(HarvestPath)' == '' ">"@(ProjectReference.TargetDir)"</HarvestPath>
  <DefineConstants>HarvestPath=$(HarvestPath)</DefineConstants>
</PropertyGroup>

<ProjectReference Include="..\..\NAME.csproj">
  <Name>NAME</Name>
  <Project>SOME_GUID</Project>
  <Private>True</Private>
  <DoNotHarvest>True</DoNotHarvest>
  <RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>
  <RefTargetDir>INSTALLFOLDER</RefTargetDir>
</ProjectReference>

如何访问项目引用的目标目录? "@(ProjectReference)"只提供了其 .csproj 文件的完整路径,我找不到任何相关文档。

好的,所以我找到了一个解决方法,以防有人感兴趣。 我只是用了"$(SolutionDir)\MY_PROJECT_FOLDER\MY_PROJECT_TARGET"。这不是完全我的目标,但它有效。

我找到了一种更可靠的方法,尽管它有点复杂。我必须这样做以支持使用更新的构建模板 (GitTemplate.12.xaml) 在 TFS 构建服务器上构建,因为:

  • 构建实际上并没有写入项目中指定的 OutputPath(例如 bin\Release\AnyCPU),而是写入了它自己的构建输出文件夹。
  • 构建 写入 IntermediateOutputPath(例如 obj\Release\AnyCPU),但不会复制 heat.exe 需要的依赖项。

这是通过查找项目输出的实际去向 (_GatheredProjectReferencePaths) 来实现的,wix2010.targets 已经通过 MSBuild task 方便地为我们获得了这些输出。它将相关信息收集到项目集合 (COMProjects) 中,HeatCOMProjects 目标循环遍历该项目集合。

您需要将"ACME.Core"、"ACME.Data"等替换为您正在加热的代码项目的名称,并确保WiX项目引用它们。您还需要确保 HeatFile 命令具有正确的参数,尤其是 DirectoryRefId,我认为需要指向目标系统上 DLL 的安装位置。

<!-- Find where the .dll and .tlb files of source projects were written to.
     Can't rely on relative paths like "$(ProjectDir)..\..\ACME\ACME.Core\bin$(ConfigurationName)\AnyCPU\ACME.Core.dll"
     because some build templates don't actually write to OutputPath.  Can't rely on the intermediate output path either
     (obj\...) because Heat needs to be able to find dependencies of any DLLs given. -->
<Target Name="GetCOMProjects" DependsOnTargets="ResolveProjectReferences">
  <ItemGroup>
    <COMProjects Include="%(_GatheredProjectReferencePaths.Name)"
                 Condition="%(_GatheredProjectReferencePaths.Name) == 'ACME.Core' Or
                            %(_GatheredProjectReferencePaths.Name) == 'ACME.Data' ">
      <Name>%(_GatheredProjectReferencePaths.Name)</Name>
      <DLLPath>%(_GatheredProjectReferencePaths.FullPath)</DLLPath>
      <TLBPath>$([System.IO.Path]::GetDirectoryName(%(_GatheredProjectReferencePaths.FullPath)))\%(_GatheredProjectReferencePaths.Filename).tlb</TLBPath>
    </COMProjects>
  </ItemGroup>
</Target>

<!-- Loop through each COMProjects item -->
<Target Name="HeatCOMProjects"
        Inputs="%(COMProjects.DLLPath); %(COMProjects.TLBPath)"
        Outputs="$(ProjectDir)%(COMProjects.Name).REGASM.wxs; $(ProjectDir)%(COMProjects.Name).REGTLB.wxs">
  <HeatFile
    ToolPath="$(WixToolPath)"
    File="%(COMProjects.DLLPath)"
    OutputFile="$(ProjectDir)%(COMProjects.Name).REGASM.wxs"
    GenerateGuidsNow="true"
    NoLogo="true"
    ComponentGroupName="%(COMProjects.Name).REGASM"
    DirectoryRefId="INSTALLDIR"
    SuppressRootDirectory="true"
    PreprocessorVariable="var.%(COMProjects.Name).TargetDir"
  />
  <HeatFile
    ToolPath="$(WixToolPath)"
    File="%(COMProjects.TLBPath)"
    OutputFile="$(ProjectDir)%(COMProjects.Name).REGTLB.wxs"
    GenerateGuidsNow="true"
    NoLogo="true"
    ComponentGroupName="%(COMProjects.Name).REGTLB"
    DirectoryRefId="INSTALLDIR"
    SuppressRootDirectory="true"
    PreprocessorVariable="var.%(COMProjects.Name).TargetDir"
  />
</Target>

<!-- Run Heat after building dependencies, but before building this project. -->
<Target Name="AfterResolveReferences" DependsOnTargets="GetCOMProjects; HeatCOMProjects" />