【问题标题】:Include MajorVersion etc in filename (OutputName) when building MSI file (wix project)构建 MSI 文件(wix 项目)时,在文件名(OutputName)中包含 MajorVersion 等
【发布时间】:2012-08-24 20:44:28
【问题描述】:

在我的 Defines.wxi 中有:

<?define MajorVersion="1" ?>
<?define MinorVersion="08" ?>
<?define BuildVersion="11" ?>

在我的 MyProject.Setup.wixproj 我有:

<OutputName>MyProject</OutputName>
<OutputType>Package</OutputType>

是否可以以某种方式在文件名中包含版本变量,以便我的文件可以命名为 MyProject.1.08.11.msi?

这不起作用(没有定义这样的变量):

<OutputName>MyProject-$(MajorVersion)</OutputName>
<OutputType>Package</OutputType>

这不起作用(没有定义这样的变量):

<Target Name="AfterBuild" Condition="'$(Configuration)' == 'Release'">
    <Copy SourceFiles="$(OutputPath)$(OutputName).msi" DestinationFiles="C:\$(OutputName)-$(MajorVersion).msi" />
</Target>

我似乎很清楚 $(MajorVersion) 不是从 Defines.wxi 文件中获取定义的正确方法。是什么?


更新

我试图把它放在 MyProject.Setup.wixproj 中:

<InstallerMajorVersion>7</InstallerMajorVersion>
<InstallerMinorVersion>7</InstallerMinorVersion>
<InstallerBuildNumber>7</InstallerBuildNumber>

...

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
    <OutputPath>bin\$(Configuration)\</OutputPath>
    <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
    <DefineConstants>PrebuildPath=..\..\obj\prebuild\web\;InstallerMajorVersion=$(InstallerMajorVersion);InstallerMinorVersion=$(InstallerMinorVersion);InstallerBuildNumber=$(InstallerBuildNumber)</DefineConstants>
</PropertyGroup>

这在Defines.wxi中:

<?define MajorVersion="$(var.InstallerMajorVersion)" ?>
<?define MinorVersion="$(var.InstallerMinorVersion)" ?>
<?define BuildVersion="$(var.InstallerBuildNumber)" ?>
<?define Revision="0" ?>
<?define VersionNumber="$(var.InstallerMajorVersion).$(var.InstallerMinorVersion).$(var.InstallerBuildNumber)" ?>

也没有用。收到以下错误消息:

  • Product/@Version 属性的值“..”不是有效版本。 合法版本值应类似于“x.x.x.x”,其中 x 是整数 从 0 到 65534。
  • 未找到 Product/@Version 属性;它是 必填。

【问题讨论】:

    标签: visual-studio-2010 msbuild wix windows-installer


    【解决方案1】:

    一种方法是在您的 MSBuild 脚本中定义变量,并在构建时更新 Defines.wxi,如 this example

    在您的 MSBuild 脚本中,您可以按如下方式定义版本属性:

      <PropertyGroup>
        <MajorVersion>1</MajorVersion>
        <MinorVersion>08</MinorVersion>
        <BuildVersion>11</BuildVersion>
        <WixConfigPath>.\Defines.wxi</WixConfigPath>
    
        <_VariableDefinitions>
          <Root>
            <VariableDefinition Name="MajorVersion" NewValue="$(MajorVersion)" />
            <VariableDefinition Name="MinorVersion" NewValue="$(MinorVersion)" />
            <VariableDefinition Name="BuildVersion" NewValue="$(BuildVersion)" />
          </Root>
        </_VariableDefinitions>
      </PropertyGroup>
    
      <Target Name="UpdateWixVars">
        <WixVarSubstitution SourceFile="$(WixConfigPath)" VariableDefinitions="$(_VariableDefinitions)"/>
      </Target>
    

    然后运行 ​​UpdateWixVars 目标将使用 MSBuild 项目中指定的版本号更新 Defines.wxi 中的版本号。

    请注意,我无法使用此自定义构建任务找到实际编译的 dll,因此我必须通过以下方式创建它:

    1. 下载源代码from here。构建它并将文件命名为 Tranxition.BuildTasks.dll。
    2. 像这样添加对构建任务的引用:

      <UsingTask TaskName="WixVarSubstitution"
           AssemblyFile="$(MSBuildExtensionsPath)\Tranxition\Tranxition.BuildTasks.dll"/>
      

    【讨论】:

    • 感谢您的回答。很想在不使用 Tranxition 的情况下修复它。我用我最近的尝试更新了我的问题,这有点相似。你对此有什么意见吗?
    • 虽然这个答案有效,但它涉及为每个构建手动更新一个文件,我更喜欢下面的答案,它可以自动化这个过程
    【解决方案2】:

    无法从 .wixproj 文件中读取 .wxi 文件。所以你必须使用另一种方式来指定版本。我可以举一个例子,我从安装程序中包含的程序集中读取版本,并使用该版本重命名 msi;

    在编辑器中打开 .wixproj 文件并添加 ReadVersion 目标:

      <Target Name="ReadVersion">
        <GetAssemblyIdentity AssemblyFiles="bin\program.exe">
          <Output TaskParameter="Assemblies" ItemName="MyAssemblyIdentities" />
        </GetAssemblyIdentity>
        <Message Text="AssemblyVersion = %(MyAssemblyIdentities.Version)" />
        <CreateProperty Value="$(TargetName) %(MyAssemblyIdentities.Version)">
          <Output TaskParameter="Value" PropertyName="TargetName" />
        </CreateProperty>
        <CreateProperty Value="$(TargetName)$(TargetExt)">
          <Output TaskParameter="Value" PropertyName="TargetFileName" />
        </CreateProperty>
        <CreateProperty Value="$(OutDir)$(TargetFileName)">
          <Output TaskParameter="Value" PropertyName="TargetPath" />
        </CreateProperty>
      </Target>
    

    这会从bin\program.exe 读取版本,显示它以进行调试,并更改 TargetName、TargetFileName 和 TargetPath。

    在包含&lt;Import Project="$(WixTargetsPath)" /&gt; 的行之后,添加以下内容以将此目标注入到构建过程中:

      <PropertyGroup>
        <BuildDependsOn>ReadVersion;$(BuildDependsOn)</BuildDependsOn>
      </PropertyGroup>
    

    【讨论】:

    • 我用我最近的尝试更新了我的问题。现在可能更清楚了。
    • 那么你必须在wixproj中使用DefineConstantsPropertyGroup,见stackoverflow.com/a/627279/33499
    • 是的,我也这样做了,现在粘贴。在我看来是正确的,但仍然出现该错误
    • 这是一个很好的解决方案,因为它会在安装文件名中自动包含主程序集的版本号,而不必手动更新文件。
    • 对我来说,这是孤立的,但不适用于我的引导程序项目。使用对 msi 的项目引用的引导程序仍在寻找安装程序的 outputname.targetext...而不是 targetfilename。
    【解决方案3】:

    这就是我最终的结果,而且它有效!

    Setup.Version.proj

    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
        <PropertyGroup>
            <InstallerMajorVersion>55</InstallerMajorVersion>
            <InstallerMinorVersion>66</InstallerMinorVersion>
        <InstallerBuildVersion>$(BuildNumber)</InstallerBuildVersion>
            <InstallerBuildVersion Condition="$(InstallerBuildVersion) == ''">0</InstallerBuildVersion>
      </PropertyGroup>
    </Project>
    

    MyProject.Setup.wixproj

    <?xml version="1.0" encoding="utf-8"?>
    <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <Import Project="Setup.Version.proj" />
      <PropertyGroup>
        <OutputName>MyProject_$(InstallerMajorVersion)_$(InstallerMinorVersion)_$(InstallerBuildVersion)</OutputName>
        <OutputType>Package</OutputType>
        <DefineConstants>InstallerMajorVersion=$(InstallerMajorVersion);InstallerMinorVersion=$(InstallerMinorVersion);InstallerBuildVersion=$(InstallerBuildVersion)</DefineConstants>
        ...
    

    Defines.wxi

    <?define MajorVersion="$(var.InstallerMajorVersion)" ?>
    <?define MinorVersion="$(var.InstallerMinorVersion)" ?>
    <?define BuildVersion="$(var.InstallerBuildVersion)" ?>
    

    【讨论】:

    • so... 在尝试了很多之后,我发现它的工作原理和描述的一样,而且 defines.wxi 不是必需的。但是我被困了一段时间,因为我确实从网上复制粘贴了&lt;DefineConstants&gt; 位,并且不知何故有一个特殊字符或VS不接受的东西 - 我总是得到var.InstallerMajorVersion not found 错误。毕竟它工作得很好,恕我直言非常优雅的解决方案!
    • 刚刚发现另一个潜在错误:您要确保&lt;DefineConstants&gt; 标记未在另一个PropertyGroup 中定义,否则您会收到var.InstallerMajorVersion not found 错误。
    • 如果您更改版本号并且您的项目加载到安装了 WiX Visual Studio 扩展的 Visual Studio 解决方案中,您必须关闭并重新打开整个解决方案才能使更改生效。即使您卸载并重新加载 WiX 项目, 数据也会以某种方式保留。
    【解决方案4】:

    在您的 .wixproj 文件中。在 &lt;/Project&gt; 标记之前添加以下部分。

    <!-- rename the output msi with Version number -->
      <Target Name="AfterBuild">
        <GetAssemblyIdentity AssemblyFiles="[Path of the main assembly with the assembly version number you want to use]">
          <Output TaskParameter="Assemblies" ItemName="AssemblyVersion"/>
        </GetAssemblyIdentity>
        <Copy SourceFiles=".\bin\$(Configuration)\$(OutputName).msi" DestinationFiles=".\bin\$(Configuration)\$(OutputName)_%(AssemblyVersion.Version).msi" />
        <Delete Files=".\bin\$(Configuration)\$(OutputName).msi" />
      </Target>
    

    这对我有用。

    【讨论】:

      【解决方案5】:

      这个常见的任务应该在 WiX 的未来版本中得到简化!

      此解决方案结合了@Wimmel 和this post。它从目标 .exe 中提取版本,否则不在文件中存储版本号;它不会在构建后重命名输出文件。但是,有必要更新属性 ProjectDefineConstants,从中派生蜡烛参数(在 wix.targets 中)。否则,仅更新 TargetPath 属性不会更改烛台.exe 的输入。

      *.wixproj:

      <Import Project="$(WixTargetsPath)" />
      <Target Name="BeforeBuild">
        <!-- Read the version from the to-be-installed .exe -->
        <GetAssemblyIdentity AssemblyFiles="path.to.primary.exe">
          <Output TaskParameter="Assemblies" ItemName="AsmInfo" />
        </GetAssemblyIdentity>
      
        <!-- Create the MSBuild property $(VersionNumber) -->
        <CreateProperty Value="%(AsmInfo.Version)">
          <Output TaskParameter="Value" PropertyName="VersionNumber" />
        </CreateProperty>
      
        <!-- Create the WiX preprocessor variable $(var.VersionNumber) -->
        <CreateProperty Value="$(DefineConstants);VersionNumber=$(VersionNumber)">
          <Output TaskParameter="Value" PropertyName="DefineConstants" />
        </CreateProperty>
      
        <!-- Update the MSBuild properties $(TargetName), etc. -->
        <CreateProperty Value="$(SolutionName)-$(Platform)-$(VersionNumber)">
          <Output TaskParameter="Value" PropertyName="TargetName" />
        </CreateProperty>
        <CreateProperty Value="$(TargetName)$(TargetExt)">
          <Output TaskParameter="Value" PropertyName="TargetFileName" />
        </CreateProperty>
        <CreateProperty Value="$(TargetName)$(TargetPdbExt)">
          <Output TaskParameter="Value" PropertyName="TargetPdbName" />
        </CreateProperty>
        <CreateProperty Value="$(TargetDir)$(TargetFileName)">
          <Output TaskParameter="Value" PropertyName="TargetPath" />
        </CreateProperty>
        <CreateProperty Value="$(TargetPdbDir)$(TargetPdbName)">
          <Output TaskParameter="Value" PropertyName="TargetPdbPath" />
        </CreateProperty>
      
        <!-- Update the MSBuild property from which candle.exe args are derived -->
        <CreateProperty Value="
          Configuration=$(ConfigurationName);
          OutDir=$(OutDir);
          Platform=$(PlatformName);
          ProjectDir=$(ProjectDir);
          ProjectExt=$(ProjectExt);
          ProjectFileName=$(ProjectFileName);
          ProjectName=$(ProjectName);
          ProjectPath=$(ProjectPath);
          TargetDir=$(TargetDir);
          TargetExt=$(TargetExt);
          TargetFileName=$(TargetFileName);
          TargetName=$(TargetName);
          TargetPath=$(TargetPath);
        ">
          <Output TaskParameter="Value" PropertyName="ProjectDefineConstants" />
        </CreateProperty>
      </Target>
      

      *.wxs

      <Product Id="*" Version="$(var.VersionNumber)" ... >
        ...
      </Product>
      

      【讨论】:

      • 优秀。最佳解决方案。
      • @l33t 为什么?这个解决方案有什么问题?您的链接目前对我不起作用...
      • @Steve Mitchell thx 这对我有用。有没有比这更简单的爬取项目可执行文件的方法:$(ProjectDir)..\MyName\bin\$(Configuration)\MyExeName.exe?此外,如果安装程序是使用调试二进制文件编译的,是否可以在 msi 名称中添加“Beta”?
      • @l33t 感谢链接!我检查了candle.exe 为我打印了-d"TargetFileName=Correct Modified Name Including Version.msi",所以我认为这是固定的。
      【解决方案6】:

      您可以通过实现这两个答案无缝地完成此任务:

      其他答案太复杂了!

      PS:如果你想去掉第四位,按照语义版本控制,你可以这样做:

      <Target Name="AfterBuild">
          <GetAssemblyIdentity AssemblyFiles="..\Path\To\MyProject\bin\$(Platform)\$(Configuration)\MyProject.dll">
              <Output TaskParameter="Assemblies" ItemName="AssemblyInfo" />
          </GetAssemblyIdentity>
          <PropertyGroup>
              <In>%(AssemblyInfo.Version)</In>
              <Pattern>^(\d+.\d+.\d+)</Pattern>
              <AssemblyVersion>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern)))</AssemblyVersion>
          </PropertyGroup>
          <Move SourceFiles="bin\$(Platform)\$(Configuration)\MyProject.msi" DestinationFiles="bin\$(Platform)\$(Configuration)\CodeGenerator-$(AssemblyVersion).$(Platform).msi" />
      </Target>
      

      这将创建一个名为 MyProject-1.2.3.x64.msi 的 MSI。请参阅this answer 了解更多信息。

      【讨论】:

      【解决方案7】:

      这是一个完整的 wixproj 文件示例,您可以在其中设置 UI 中的版本号并使用它来修改输出 msi 文件名。

      在 Visual Studio 中(例如 2015):

      • 在“定义预处理器变量”中定义版本号 项目属性窗口。我为此输入了 VersionNumber=1.14 示例;
      • 在解决方案资源管理器中卸载您的项目;
      • 在解决方案资源管理器中右键单击您的项目并选择编辑 yourproject.wixproj 文件;
      • 在 Target Name="BeforeBuild" 元素中添加代码,如下所示。

        <?xml version="1.0" encoding="utf-8"?>
        <Project ToolsVersion="4.0" DefaultTargets="Build" InitialTargets="EnsureWixToolsetInstalled" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
          <PropertyGroup>
            <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
            <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
            <ProductVersion>3.10</ProductVersion>
            <ProjectGuid>PROJECT-GUID</ProjectGuid>
            <SchemaVersion>2.0</SchemaVersion>
            <OutputName>my project</OutputName>
            <OutputType>Package</OutputType>
          </PropertyGroup>
          <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
            <OutputPath>bin\$(Configuration)\</OutputPath>
            <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
            <!-- These constants can be set in the UI -->
            <DefineConstants>VersionNumber=1.14</DefineConstants>
          </PropertyGroup>
          <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
            <OutputPath>bin\$(Configuration)\</OutputPath>
            <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
            <DefineConstants>VersionNumber=1.14</DefineConstants>
          </PropertyGroup>
          <ItemGroup>
            <Compile Include="Product.wxs" />
          </ItemGroup>
          <ItemGroup>
            <WixExtension Include="WixUIExtension">
              <HintPath>$(WixExtDir)\WixUIExtension.dll</HintPath>
              <Name>WixUIExtension</Name>
            </WixExtension>
          </ItemGroup>
          <Import Project="$(WixTargetsPath)" Condition=" '$(WixTargetsPath)' != '' " />
          <Import Project="$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets" Condition=" '$(WixTargetsPath)' == '' AND Exists('$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets') " />
        
          <Target Name="BeforeBuild">
            <!-- This extracts the version number from a setting in the UI -->
            <!-- This method comes from: geekswithblogs.net/alexhildyard/archive/2013/03/09/passing-data-between-msbuild-and-wix.aspx -->
            <ItemGroup>
              <DefineConstantsKVPairs Include="$(DefineConstants)" />
            </ItemGroup>
            <!-- Evaluate each key/value pair with task batching, then make a conditional assignment -->
            <PropertyGroup>
              <VersionNumber Condition="$([System.String]::new('%(DefineConstantsKVPairs.Identity)').Contains('VersionNumber='))">$([System.String]::new('%(DefineConstantsKVPairs.Identity)').Split('=')[1])</VersionNumber>
            </PropertyGroup>
        
            <CreateProperty Value="$(OutputName)-$(VersionNumber)">
              <Output TaskParameter="Value" PropertyName="TargetName" />
            </CreateProperty>
            <CreateProperty Value="$(TargetName)$(TargetExt)">
              <Output TaskParameter="Value" PropertyName="TargetFileName" />
            </CreateProperty>
            <CreateProperty Value="$(TargetDir)$(TargetFileName)">
              <Output TaskParameter="Value" PropertyName="TargetPath" />
            </CreateProperty>
          </Target>
        </Project>
        

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-17
        • 1970-01-01
        • 2011-10-03
        • 2010-09-21
        • 2013-01-24
        相关资源
        最近更新 更多