在MSBuild中将程序集版本号作为命令行参数指定

44

我希望能够像这样使用MSBuild命令行参数指定在构建期间生成的所有程序集的版本号:

MSBuild.exe /p:version=5.4.3.0 

我查看了AssemblyInfoTask,但在这种情况下,它似乎不是一个好的解决方案。


为什么AssemblyInfo任务对你来说不合适?它的目的就是设置程序集信息,包括版本号(AssemblyVersion)属性。 - DaveE
版本号需要根据一些外部规则进行设置,而不是使用AssemblyInfoTask内置的规则进行设置。基本上,我希望命令行参数成为版本号。 - Radu M.
我使用了 https://www.nuget.org/packages/MSBuild.AssemblyVersion/ 包来实现这个功能。 - GKalnytskyi
5个回答

47

对于使用dotnet.exe构建的SDK-style项目,程序集版本属性将自动生成,因此您可以直接使用/p:Version=5.4.3.0

如果使用旧的项目格式,则需要在.csproj文件中添加以下BeforeBuild步骤。不需要使用额外的.targets和扩展包,因为MSBuild已经有了一个内置任务,它可以完成大部分工作:

<Target Name="BeforeBuild">
  <ItemGroup>
    <AssemblyAttributes Include="AssemblyVersion">
      <_Parameter1>$(Version)</_Parameter1>
    </AssemblyAttributes>
  </ItemGroup>
  <MakeDir Directories="$(IntermediateOutputPath)" />
  <WriteCodeFragment Language="C#"
                     OutputFile="$(IntermediateOutputPath)Version.cs"
                     AssemblyAttributes="@(AssemblyAttributes)" />
  <ItemGroup>
    <Compile Include="$(IntermediateOutputPath)Version.cs" />
  </ItemGroup>
</Target>

请确保删除现有的 AssemblyVersion 属性,因为它会在编译期间生成。

更新于2020年7月29日: Michael Parker 指出,如果您使用此方法并从 Visual Studio 进行构建,则会在 Version.cs 文件中得到一个空版本。为了解决这个问题,我建议在您的 .csprojDirectory.Build.props 文件中定义默认的版本值,如下所示:

<PropertyGroup>
  ...
  <Version Condition="'$(Version)' == ''">1.0.0.0</Version>
</PropertyGroup>

如果命令行没有指定版本,这将把它设置为1.0.0.0


2
自己注意:不要忘记 .Net Framework 项目也可以使用 SDK 样式的项目文件! - Gerardo Grignoli
1
@MichaelParker 谢谢您指出这一点。我已经更新了答案。 - Yarik
2
<Target Name="BeforeBuild"> 应该在 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />之后指定,因为我刚学到这个。 - oleksa
如果您有一个名为 Properties\AssemblyInfo.cs 的文件,您需要注释掉以下两行代码:[assembly: AssemblyVersion[assembly: AssemblyFileVersion - daniol
感谢@oleksa!你的评论很重要。 - Sahitya
显示剩余2条评论

22

我知道这是一个老问题,但谷歌把我带到了这里作为最佳结果。

我在更新的链接中遵循了一个简单的解决方案(感谢Peter提供的更新链接)。不需要扩展包。

基本上你需要做的就是添加一个“BuildCommon.targets”文件,并相应地修改你的csproj文件,以便在msbuild中指定版本号,例如:

msbuild.exe abc.sln /p:Configuration=Release;VersionAssembly=1.2.3.4

希望这能有所帮助。

1
@Freidgeim:那取决于你在BuildCommon.targets文件中命名该命令开关的方式。这完全取决于你自己 :) - Jach
4
2019年了,这仍然是设置一些版本号的最简单解决方案... 唉。微软,请修复它。 - ebol2000
5
他们做了这件事情,对于dotnet.exe,你可以像这样指定:/p:Version=1.2.4 - CubanX
这对我非常有效。链接的文章非常有启发性。唯一的问题是,在我的AssemblyInfo.cs文件中,我使用的是1.0.*而不是正则表达式所寻找的1.0.0.0。一旦我纠正了这个问题,它就像魔法般地运行了。 - galamdring
1
请在此处查看链接:https://web.archive.org/web/20210118064331/http://www.lionhack.com/2014/02/13/msbuild-override-assembly-version/ - Peter
显示剩余2条评论

20

我经常像您在评论中描述的那样使用AssemblyInfo任务。

  <!-- update standard assembly attribute in all projects -->
  <Target Name="BeforeBuild" >
    <Message Text="Updating AssemblyInfo to Version $(VersionNumber)"></Message>
    <Message Text="Writing to AssemblyInfo files in $(SolutionRoot)"></Message>
    <AssemblyInfo AssemblyInfoFiles="@(AssemblyInfoFiles)" 
                  AssemblyCopyright="$(AssemblyCopyright)" 
                  AssemblyVersion="$(VersionNumber)"
                  AssemblyFileVersion="$(VersionNumber)"
                  >
    </AssemblyInfo>
  </Target>

VersionNumber的值从MSBuild项目文件外部传递,正如您所描述的那样:

  MSBuild <project_file> /p:VersionNumber=<value>;...

我们使用BeforeBuild目标来确保在构建开始之前所有的AssemblyInfo.cs文件都得到处理。这不是你想要的吗?


2
当我尝试这样做时,出现了一个错误,指出找不到AssemblyInfo任务。 我谷歌搜索了“AssemblyInfo任务”,并安装了一个名为MSBuild扩展的东西,但是那不起作用。 您能提供您使用的链接吗? - CoderDennis
@DennisPalmer,我们使用来自MSBuild扩展包的任务。将...tasks文件包含在PropertyGroup元素中,你就可以开始了。 - DaveE
安装那个扩展包并没有帮助,我仍然遇到了错误,所以我在这里打开了 Stack Overflow 的问题链接 http://stackoverflow.com/questions/13090933/assemblyinfo-not-found-and-msbuild-extension-pack-installed。 - Dean Hiller
3
你们中的一位能否在GitHub上提供一个最小可行示例? - dfsg76
需要哪个Tasks文件?我们只需将其添加到我们的解决方案中吗? - FlappySocks
@FlappySocks 这是我们构建过程中的简化版本:`<PropertyGroup> <TPath>C:\Program Files (x86)\MSBuild\ExtensionPack\4.0\MSBuild.ExtensionPack.tasks</TPath> </PropertyGroup><Import Project="$(TPath)"/> <Target Name="BuildApplication"> ... <MSBuild Projects="AppAssemblyInfo.proj" <--旋转 AssemblyInfo.cs 文件 Properties="MajorMinor=$(MajorMinor);VersionNumber=$(VersionNumber);ReleaseName=$(ReleaseName)" ToolsVersion="14.0" Targets="SetAllValues" ContinueOnError="false" /> ... 构建过程的其余部分 ` - DaveE

7
顶部的答案很好,但我需要做一些调整。我们的解决方案包含混合SDK和非SDK项目。此外,我们还使用 AspNetCompileMerge 预编译 ASP.NET MVC 5 视图。使用属性名称 AssemblyAttributes 导致 GenerateAssemblyInfo 的目标从 AspNetCompileMerge.targets 执行并失败。因此,最终我使用以下目标,在整个解决方案中通过 Directory.Build.props 共享:
<PropertyGroup>
    <Version Condition="'$(Version)' == ''">1.0.0.0</Version>
    <AssemblyVersion Condition="'$(AssemblyVersion)' == ''">$(Version.Split('-')[0])</AssemblyVersion>
    <FileVersion Condition="'$(FileVersion)' == ''">$(Version.Split('-')[0])</FileVersion>
    <InformationalVersion Condition="'$(InformationalVersion)' == ''">$(Version)</InformationalVersion>
</PropertyGroup>
<Target Name="NonSdkGenerateAssemblyInfo" DependsOnTargets="PrepareForBuild" BeforeTargets="BeforeBuild" Condition="('$(UsingMicrosoftNETSdk)' != 'True' And '$(GenerateAssemblyInfo)' != 'False')">
    <ItemGroup>
        <NonSdkAssemblyAttributes Include="AssemblyVersion">
            <_Parameter1>$(AssemblyVersion)</_Parameter1>
        </NonSdkAssemblyAttributes>
        <NonSdkAssemblyAttributes Include="AssemblyFileVersion">
            <_Parameter1>$(FileVersion)</_Parameter1>
        </NonSdkAssemblyAttributes>
        <NonSdkAssemblyAttributes Include="AssemblyInformationalVersion">
            <_Parameter1>$(InformationalVersion)</_Parameter1>
        </NonSdkAssemblyAttributes>
    </ItemGroup>
    <WriteCodeFragment AssemblyAttributes="@(NonSdkAssemblyAttributes)"
                       Language="C#"
                       OutputDirectory="$(IntermediateOutputPath)"
                       OutputFile="AssemblyInfo.cs">
        <Output TaskParameter="OutputFile" ItemName="Compile" />
        <Output TaskParameter="OutputFile" ItemName="FileWrites" />
    </WriteCodeFragment>
</Target>

如果需要,您可以添加其他属性。默认版本号为1.0.0.0,您可以在命令行上指定其他版本号,模仿SDK行为:

  • AssemblyVersionFileVersion默认值为$(Version)的值,不包括后缀。例如,如果$(Version)1.2.3-beta.4,那么该值将是1.2.3
  • InformationalVersion默认值为$(Version)的值。

这个很好用!我尝试了很多解决方案,有些带扩展名,有些不带 - 在CLI中使用单个版本并让它处理所有设置。干杯! - Poat

2

顶级答案确实很好。此外,以下是一些可能有用的澄清/建议(也许从上面的帖子中显而易见),以避免任何自定义目标、BeforeBuild等。

  • 对于 SDK 项目(即没有 AssemblyInfo.cs 的项目):/p:Version='1.0.0-patch' 也适用于 msbuild.exe(当然也适用于 dotnet.exe),无需 任何 csproj 更改。例如,在针对仍然不支持 dotnet.exe 的 v3 Wix 安装程序项目时非常有用。此外,您可以将 $AssemblyVersion 和 $FileVersion 分配为空值,因为 $Version 将自动分配它们。
  • 对于非 SDK 项目,与其使用自定义目标、BeforeBuild 等修改 csproj,不如将其升级为 SDK 样式项目,即删除过时的 AssemblyInfo.cs 使用。请参阅 迁移项目

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接