【问题标题】:How to order the harvesting of file before compilation?如何在编译前订购文件的收获?
【发布时间】:2014-12-03 21:09:48
【问题描述】:

我使用_PublishedApplications 在 TFS 构建服务器中生成结构。在此之后,我使用 WiX 项目中的<HeatDirectory> 来正确获取 _PublishedApplications 文件夹的内容。但我的问题是构建期间的顺序。

如果我在<Target Name="BeforeBuild"> 中使用<HeatDirectory>,它不包括复制到_PublishedApplications 的二进制文件,因为收集是在发布(文件复制)之前执行的。

如果我将目标更改为BeforeCompile,则编译不会成功,因为首先没有文件。这是 WiX 项目的代码(它的相关部分):

  <ItemGroup>
    <Compile Include="Product.wxs" />
    <Compile Include="Autogenerated.wxs" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\SimpleProject\SimpleProject.csproj">
      <Name>SimpleProject</Name>
      <Project>{GUID}</Project>
      <Private>True</Private>
      <DoNotHarvest>True</DoNotHarvest>
      <RefProjectOutputGroups>Binaries</RefProjectOutputGroups>
      <RefTargetDir>INSTALLFOLDER</RefTargetDir>
    </ProjectReference>
  </ItemGroup>
  <Import Project="$(WixTargetsPath)" />
  <Target Name="BeforeCompile">
    <HeatDirectory OutputFile="Autogenerated.wxs" Directory="$(Sources)"
                   PreprocessorVariable="var.SimpleProject.TargetDir" 
                   AutogenerateGuids="true" SuppressRegistry="true"
                   ToolPath="$(WixToolPath)" DirectoryRefId="INSTALLFOLDER"
                   ComponentGroupName="ComponentGroup_Core" 
                   SuppressRootDirectory="true" />
  </Target>

问题

在将二进制文件复制到 _PublishedApplications 后如何执行收集?

【问题讨论】:

    标签: msbuild wix tfsbuild


    【解决方案1】:

    我使用以下命令构建我的解决方案:

    msbuild SimpleInstaller.sln /p:OutDir=C:\Temp\Output\ /v:diag > C:\Temp\Log.txt
    

    这会将所有日志输出到一个文本文件。您可以改用MSBuild logger

    然后我发现当你构建一个C#项目时,文件Microsoft.Common.targets中的目标Compile被调用了。该目标有一个属性DependsOnTarget,其中包含对目标BeforeCompile 的引用。

    我可以在我自己的 C# 项目中覆盖这个目标 BeforeCompile,只需在其末尾添加以下代码(文件 .csproj):

      ...
      <Target Name="BeforeCompile">
        <!-- custom action. -->
      </Target>
    </Project>
    

    但问题是我的 WiX 项目无法覆盖 BeforeCompile 目标,因为该目标不是为 WiX 项目定义的。您可以在 wix2010.targets 文件中检查这一点。目标Compile 仅依赖于目标PrepareForBuildResolveWixExtensionReferencesGenerateCompileWithObjectPath

    我的解决方案是确定BeforeCompile 的替代方案,即Harvest 目标。我的 WiX 项目 (.wixproj) 现在有以下目标:

    <Target Name="Harvest">
      <HeatDirectory OutputFile="Autogenerated.wxs" Directory="$(Sources)"
                     PreprocessorVariable="var.SimpleProject.TargetDir" 
                     AutogenerateGuids="true" SuppressRegistry="true"
                     ToolPath="$(WixToolPath)" DirectoryRefId="INSTALLFOLDER"
                     ComponentGroupName="ComponentGroup_Core" 
                     SuppressRootDirectory="true" />
    </Target>
    

    所有这些问题都发生了,因为我在解决方案中的第一个项目是 WiX 项目,然后我才添加了 C# 项目。出于这个原因,BeforeBuild 在其他所有事情之前被执行。

    解决此问题的另一个解决方案是编辑解决方案文件(.sln)并将解决方案文件开头的 WiX 项目声明移动到所有项目声明的末尾(而不是末尾解决方案文件)。那么在C#项目创建_PublishedApplications文件夹后,就会执行WiX项目的BeforeBuild

    此手动编辑是必需的,因为如果您更改项目构建顺序,您实际上是在更改项目引用(至少在解决方案文件中),但目标 BeforeBuild 在负责的 ResolveProjectReferences 之前被调用用于调用任何引用的构建。

    这是应该在所有其他人之后的项目声明:

    Project("GUID") = "SimpleInstaller", "SimpleInstaller\SimpleInstaller.wixproj", "GUID"
    EndProject
    

    我的建议仍然是使用Harvest 目标,因为它独立于解决方案文件中的任何更改。

    【讨论】:

    • 您不应该直接编辑您的解决方案文件。 VS中有一个选项可以做到这一点。请查看我的回答中的更新。
    • 即使你改变了项目构建顺序,当你执行构建时,第一个目标是文件中的第一个项目。然后,调用第一个项目的 BeforeBuild。只有在调用了 BeforeBuild 之后,才会调用 ResolveProjectReferences,所以即使你通过添加项目引用来更改构建顺序,在这种特殊情况下它也不起作用。
    • 我有一个解决方案文件(VS 2013u5 - 12.0.40629.0),其中 .wixproj 在文件中最后定义(项目引用),但我仍在观察 BeforeBuild 目标的行为.wixproj 的 .wixproj 在依赖项目构建之前被调用。
    【解决方案2】:

    您需要做的第一件事是将安装程序项目中的项目引用添加到应用程序项目中。这将强制应用程序构建并可供您的安装程序项目使用。

    如果您需要更改您需要配置项目依赖项的顺序,您可以在 VisualStudio 下右键单击您的解决方案并单击“项目构建顺序...”来验证项目的构建顺序。

    然后在您的安装程序项目中执行以下操作:

        <PropertyGroup>
            <RootDir>{PATH TO _PublishedApplications FOLDER}</RootDir>
            <HarvestDirectoryNoLogo>true</HarvestDirectoryNoLogo>
            <HarvestDirectorySuppressAllWarnings>false</HarvestDirectorySuppressAllWarnings>
            <HarvestDirectoryTreatWarningsAsErrors>false</HarvestDirectoryTreatWarningsAsErrors>
            <HarvestDirectoryTreatSpecificWarningsAsErrors>
            </HarvestDirectoryTreatSpecificWarningsAsErrors>
            <HarvestDirectoryVerboseOutput>false</HarvestDirectoryVerboseOutput>
            <HarvestDirectoryAutogenerateGuids>false</HarvestDirectoryAutogenerateGuids>
            <HarvestDirectoryGenerateGuidsNow>true</HarvestDirectoryGenerateGuidsNow>
            <HarvestDirectorySuppressFragments>true</HarvestDirectorySuppressFragments>
            <HarvestDirectorySuppressUniqueIds>false</HarvestDirectorySuppressUniqueIds>
        </PropertyGroup>
        <Import Project="$(WixTargetsPath)" />
        <Target Name="BeforeBuild">
            <ItemGroup>
                <HarvestDirectory Include="$(RootDir)">
                    <Transforms>
                    </Transforms>
                    <ComponentGroupName>MyComponent</ComponentGroupName>
                    <DirectoryRefId>WebSiteRoot</DirectoryRefId>
                    <PreprocessorVariable>var.RootDir</PreprocessorVariable>
                    <SuppressCom>false</SuppressCom>
                    <SuppressRegistry>false</SuppressRegistry>
                    <SuppressRootDirectory>true</SuppressRootDirectory>
                    <KeepEmptyDirectories>true</KeepEmptyDirectories>
                </HarvestDirectory>
            </ItemGroup>
            <HeatDirectory 
                NoLogo="$(HarvestDirectoryNoLogo)" 
                SuppressAllWarnings="$(HarvestDirectorySuppressAllWarnings)" 
                SuppressSpecificWarnings="$(HarvestDirectorySuppressSpecificWarnings)" 
                ToolPath="$(WixToolPath)" 
                TreatWarningsAsErrors="$(HarvestDirectoryTreatWarningsAsErrors)" 
                TreatSpecificWarningsAsErrors="$(HarvestDirectoryTreatSpecificWarningsAsErrors)" 
                VerboseOutput="$(HarvestDirectoryVerboseOutput)" 
                AutogenerateGuids="$(HarvestDirectoryAutogenerateGuids)" 
                GenerateGuidsNow="$(HarvestDirectoryGenerateGuidsNow)" 
                OutputFile="$(IntermediateOutputPath)_%(HarvestDirectory.Filename)_dir.wxs" 
                SuppressFragments="$(HarvestDirectorySuppressFragments)" 
                SuppressUniqueIds="$(HarvestDirectorySuppressUniqueIds)" 
                Transforms="%(HarvestDirectory.Transforms)" 
                Directory="@(HarvestDirectory)" 
                ComponentGroupName="%(HarvestDirectory.ComponentGroupName)" 
                DirectoryRefId="%(HarvestDirectory.DirectoryRefId)" 
                KeepEmptyDirectories="%(HarvestDirectory.KeepEmptyDirectories)" 
                PreprocessorVariable="%(HarvestDirectory.PreprocessorVariable)" 
                SuppressCom="%(HarvestDirectory.SuppressCom)" 
                SuppressRootDirectory="%(HarvestDirectory.SuppressRootDirectory)" 
                SuppressRegistry="%(HarvestDirectory.SuppressRegistry)" />
        </Target>
    </Project>
    

    我根据HeatDirectory Task 的文档生成了这段代码,并在实际项目中使用它。

    【讨论】:

    • 这与我所做的完全相同,但它不起作用,因为复制输出的 NuGet _PublishedApplications 包中的任务是在收获之后执行的。它独立于项目的引用。
    猜你喜欢
    • 2015-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-17
    • 2018-03-23
    • 2018-01-11
    • 1970-01-01
    相关资源
    最近更新 更多