【问题标题】:Set git commit hash as dll version number in visual studio在 Visual Studio 中将 git commit hash 设置为 dll 版本号
【发布时间】:2016-01-12 08:25:06
【问题描述】:

我正在使用 Visual Studio 2013 和 git 开发一个项目。

我必须分发项目的一些库,所以我想用当前的 git commit hash 设置它们的版本号,这样我就可以确定它们使用的是哪个库版本。

有没有办法以自动方式将哈希作为版本号,即使用预构建事件,而不是每次都手动执行?

【问题讨论】:

  • 我们有一堆 msbuild 代码,但我不允许分发整个代码。不确定您是否会得到帮助,但原则是:使用定义了 VERSIONINFO 结构的资源文件模板。在预构建事件中,使用git rev-parse --short HEAD 的输出(以及公司名称和诸如此类)填充模板并调用 rc.exe 以创建一个 .res 文件。所有这些代码都存储在一个属性表中,该表还将 .res 文件添加到项目的资源中。因此,您对新项目所要做的就是导入 1 个单个文件,一切正常
  • 这似乎是一个很好的解决方案,我会尝试一下。谢谢
  • Alexey 的回答应该可以帮助您入门,对于 C#,如果您愿意,我可以发布带有一些适用于 C++ 的 sn-ps 的答案
  • 是的,它会很有用

标签: git visual-studio versioning


【解决方案1】:

以下是使用资源文件的本机项目可能实现的一些 sn-ps。这个想法是向项目添加一个属性表,它有一个 prebuild 事件,它基于 git commit hash 创建一个 .res 文件,并将这个 .res 文件添加为资源。这是属性表:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ImportGroup Label="PropertySheets" />
  <PropertyGroup Label="UserMacros" />
  <PropertyGroup>
    <VersionResourceOut>$(MSBuildProjectDirectory)\version.res</VersionResourceOut>
  </PropertyGroup>
  <ItemGroup>
    <Resource Include="$(VersionResourceOut)" />
  </ItemGroup>
  <Import Project="$(BuildToolsDir)tools\versionrc.targets" />
  <Target Name="CreateGitVersionResource" BeforeTargets="BuildGenerateSources">
    <CallTarget Targets="CreateGitVersionResInBuild" />
    <MakeSameWriteTime SourceFile="$(OutDir)$(TargetName)$(TargetExt)" DestFile="$(VersionResourceOut)"/>
  </Target>
</Project>

$(BuildToolsDir)tools\versionrc.targets 文件是实际创建资源文件的位置。完整的实现相当冗长,因为它也适用于 svn 并允许进行大量自定义 - 在这里发布的内容有点多,所以我只列出它的主要内容:

  • 提交哈希存储在 msbuild 属性中,获取它的命令是

    git --work-tree=$(GitVersionDir) --git-dir=$(GitVersionDir)\.git rev-parse --short HEAD
    

    其中 $(GitVersionDir) 通常设置为 $(MsbuildProjectDirectory),因为我们在源根目录中拥有大多数 .vcxproj 文件。

  • 我也喜欢包含构建日期,因此最终进入 StringFileinfo 块的 FileDescription 条目的属性是

    <FileDesc>$(GitVersion) $([System.DateTime]::Now.ToString('HH:mm:ss dd/MM/yyyy'))</FileDesc>
    
  • 实际的文件/产品版本、公司名称和其他字段是从其他地方获取的。通常我们有一个通用的头文件定义 RC 文件模板所需的所有 VRC_XXX 宏(见下文),以及一个包含例如的每个项目的头文件。 #define VRC_FILEDESC "Project Foo",并使用 ReadLinesFromFile/WriteLinesToFile 任务合并这些标题。无论如何,这个想法是最终得到一个像

    这样的头文件
    #define VRC_FILEVERSION 4,4,1,0
    #define VRC_PRODUCTVERSION 4.4.1.0
    #define VRC_COMPANYNAME MyCompany
    #define VRC_PRODUCTNAME VRC_COMPANYNAME Libraries
    #define VRC_FILEDESC Project Foo
    #define VRC_FILEDESCRIPTION VRC_FILEDESC VRC_FILEDESCGIT
    

    谁的路径存储在 $(VersionMainInclude) 属性中。

  • 所有这些都被提供给rc.exe 以创建 .res 文件。完整的命令类似于

    rc /d VRC_INCLUDE=$(VersionMainInclude)
       /d VRC_ORIGINALFILENAME=$(TargetName)$(TargetExt)
       /d VRC_FILETYPE=$(FileType)
       /d VRC_FILEDESCGIT=$(FileDesc)
       /d VRC_COPYRIGHT=VRC_COMPANYNAME \251 $([System.DateTime]::Now.ToString(`yyyy`))
       /fo $(VersionResourceOut) $(MsBuildThisFileDirectory)version.rc
    
  • 请注意MakeSameWriteTime 将 .res 文件的修改时间设置为与输出文件相同的技巧,以确保每次生成 .res 文件时 prebuild 事件都不会触发新的构建。可能有更好的方法来做到这一点,但这个对我有用:

    <UsingTask TaskName="MakeSameWriteTime" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" >
      <ParameterGroup>
        <SourceFile Required="true" ParameterType="System.String"/>
        <DestFile Required="true" ParameterType="System.String"/>
      </ParameterGroup>
      <Task>
        <Code Type="Fragment" Language="cs">
          <![CDATA[
    System.IO.File.SetLastWriteTime( DestFile, System.IO.File.GetLastWriteTime( SourceFile ) );]]>
        </Code>
      </Task>
    </UsingTask>
    

这是使用的完整 .rc 模板:

#include <winver.h>

#define stringize( x )        stringizei( x )
#define stringizei( x )       #x

#ifdef VRC_INCLUDE
  #include stringize( VRC_INCLUDE )
#endif

#ifdef _WIN32
  LANGUAGE 0x9,0x1
  #pragma code_page( 1252 )
#endif

1 VERSIONINFO
 FILEVERSION    VRC_FILEVERSION
 PRODUCTVERSION VRC_PRODUCTVERSION
 FILEFLAGSMASK  0x1L
 FILEFLAGS      VS_FF_DEBUG
 FILEOS         VOS__WINDOWS32
 FILETYPE       VRC_FILETYPE
BEGIN
  BLOCK "StringFileInfo"
  BEGIN
    BLOCK "040904E4"
    BEGIN
      VALUE "CompanyName",      stringize( VRC_COMPANYNAME )
      VALUE "FileDescription",  stringize( VRC_FILEDESCRIPTION )
      VALUE "FileVersion",      stringize( VRC_FILEVERSION )
      VALUE "LegalCopyright",   stringize( VRC_COPYRIGHT )
      VALUE "InternalName",     stringize( VRC_ORIGINALFILENAME )
      VALUE "OriginalFilename", stringize( VRC_ORIGINALFILENAME )
      VALUE "ProductName",      stringize( VRC_PRODUCTNAME )
      VALUE "ProductVersion",   stringize( VRC_PRODUCTVERSION )
    END
  END
  BLOCK "VarFileInfo"
  BEGIN
    VALUE "Translation", 0x409, 1200
  END
END

【讨论】:

  • 非常感谢,这正是我所需要的。
【解决方案2】:

看看我在https://github.com/Bitrete/msbuildtasks 对 MSBuild 社区任务项目的修改。我添加了一个名为 SemanticVersionGitDescribe 的任务。请参阅下面的使用示例。

<SemanticVersionGitDescribe LocalPath="$(MSBuildProjectDirectory)">
    <Output TaskParameter="SemanticVersion" PropertyName="Version"/>
    <Output TaskParameter="IsRelease" PropertyName="Release"/>
    <Output TaskParameter="AdditionalCommitsCount" PropertyName="AdditionalCommits"/>
    <Output TaskParameter="Hash" PropertyName="Hash"/>
</SemanticVersionGitDescribe>

并且不要忘记将带有哈希的版本字符串仅放在AssemblyInformalVersion 属性中。因为AssemblyVersion 属性只接受由句点分隔的数字。

 <Target Name="UpdateAssemblyInfoVersion" DependsOnTargets="Prepare; GetGitVersion">
    <Copy SourceFiles="$(EtcPath)\common\CommonAssemblyInfo.cs" DestinationFiles="$(OutputPath)\CommonAssemblyInfo.cs"/>
    <FileUpdate Files="$(EtcPath)\common\CommonAssemblyInfo.cs"
        Multiline="true"
        Singleline="false"
        Regex="(AssemblyVersion)\(&quot;([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)?&quot;\)"
        ReplacementText="$1(&quot;$(Version).$(AdditionalCommits)&quot;)" />
    <FileUpdate Files="$(EtcPath)\common\CommonAssemblyInfo.cs"
        Multiline="true"
        Singleline="false"
        Regex="(AssemblyFileVersion)\(&quot;([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)?&quot;\)"
        ReplacementText="$1(&quot;$(Version).$(AdditionalCommits)&quot;)" />
    <FileUpdate Condition=" $(Release) == False " 
        Files="$(EtcPath)\common\CommonAssemblyInfo.cs"
        Multiline="true"
        Singleline="false"
        Regex="(AssemblyInformationalVersion)\(&quot;([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)?&quot;\)"
        ReplacementText="$1(&quot;$(Version).$(AdditionalCommits)-g$(Hash)&quot;)" />
    <FileUpdate Condition=" $(Release) == True "
        Files="$(EtcPath)\common\CommonAssemblyInfo.cs"
        Multiline="true"
        Singleline="false"
        Regex="(AssemblyInformationalVersion)\(&quot;([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)?&quot;\)"
        ReplacementText="$1(&quot;$(Version)&quot;)" />
</Target>

【讨论】:

    猜你喜欢
    • 2017-03-19
    • 2022-01-13
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多