将 git commit hash 设置为 visual studio 中的 dll 版本号
Set git commit hash as dll version number in visual studio
我正在使用 visual studio 2013 和 git 开发一个项目。
我必须分发项目的一些库,所以我想用当前 git 提交哈希设置它们的版本号,这样我就可以确定它们使用的是哪个库版本。
有没有办法自动将散列作为版本号,即使用预构建事件,而不是每次都手动进行?
在 https://github.com/Bitrete/msbuildtasks 查看我对 MSBuild Community Tasks 项目的修改。我添加了一个名为 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)\("([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)?"\)"
ReplacementText="("$(Version).$(AdditionalCommits)")" />
<FileUpdate Files="$(EtcPath)\common\CommonAssemblyInfo.cs"
Multiline="true"
Singleline="false"
Regex="(AssemblyFileVersion)\("([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)?"\)"
ReplacementText="("$(Version).$(AdditionalCommits)")" />
<FileUpdate Condition=" $(Release) == False "
Files="$(EtcPath)\common\CommonAssemblyInfo.cs"
Multiline="true"
Singleline="false"
Regex="(AssemblyInformationalVersion)\("([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)?"\)"
ReplacementText="("$(Version).$(AdditionalCommits)-g$(Hash)")" />
<FileUpdate Condition=" $(Release) == True "
Files="$(EtcPath)\common\CommonAssemblyInfo.cs"
Multiline="true"
Singleline="false"
Regex="(AssemblyInformationalVersion)\("([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)?"\)"
ReplacementText="("$(Version)")" />
</Target>
以下是使用资源文件的本机项目可能实现的一些片段。这个想法是向项目添加一个 属性 sheet,它有一个预生成事件,它根据 git 提交哈希创建一个 .res 文件,并且还添加了这个 .res 文件作为资源。这里是 属性 sheet:
<?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 并允许进行大量自定义 - 在这里 post 有点多,所以我只列出它的内容:
提交哈希存储在 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>
实际file/product版本、公司名称等字段是从别处获取的。通常我们有一个通用 header 文件定义 RC 文件模板(见下文)所需的所有 VRC_XXX 宏,以及一个 per-project header 文件包含例如#define VRC_FILEDESC "Project Foo",那些 header 使用 ReadLinesFromFile/WriteLinesToFile 任务合并。无论如何,我的想法是最终得到一个 header 文件,例如
#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 1 $([System.DateTime]::Now.ToString(`yyyy`))
/fo $(VersionResourceOut) $(MsBuildThisFileDirectory)version.rc
注意 MakeSameWriteTime
将 .res 文件的修改时间设置为与输出文件相同的技巧,以确保预构建事件不会在每次.res 文件生成。可能有更好的方法来做到这一点,但这个对我有用:
<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
我正在使用 visual studio 2013 和 git 开发一个项目。
我必须分发项目的一些库,所以我想用当前 git 提交哈希设置它们的版本号,这样我就可以确定它们使用的是哪个库版本。
有没有办法自动将散列作为版本号,即使用预构建事件,而不是每次都手动进行?
在 https://github.com/Bitrete/msbuildtasks 查看我对 MSBuild Community Tasks 项目的修改。我添加了一个名为 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)\("([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)?"\)"
ReplacementText="("$(Version).$(AdditionalCommits)")" />
<FileUpdate Files="$(EtcPath)\common\CommonAssemblyInfo.cs"
Multiline="true"
Singleline="false"
Regex="(AssemblyFileVersion)\("([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)?"\)"
ReplacementText="("$(Version).$(AdditionalCommits)")" />
<FileUpdate Condition=" $(Release) == False "
Files="$(EtcPath)\common\CommonAssemblyInfo.cs"
Multiline="true"
Singleline="false"
Regex="(AssemblyInformationalVersion)\("([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)?"\)"
ReplacementText="("$(Version).$(AdditionalCommits)-g$(Hash)")" />
<FileUpdate Condition=" $(Release) == True "
Files="$(EtcPath)\common\CommonAssemblyInfo.cs"
Multiline="true"
Singleline="false"
Regex="(AssemblyInformationalVersion)\("([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)?"\)"
ReplacementText="("$(Version)")" />
</Target>
以下是使用资源文件的本机项目可能实现的一些片段。这个想法是向项目添加一个 属性 sheet,它有一个预生成事件,它根据 git 提交哈希创建一个 .res 文件,并且还添加了这个 .res 文件作为资源。这里是 属性 sheet:
<?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 并允许进行大量自定义 - 在这里 post 有点多,所以我只列出它的内容:
提交哈希存储在 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>
实际file/product版本、公司名称等字段是从别处获取的。通常我们有一个通用 header 文件定义 RC 文件模板(见下文)所需的所有 VRC_XXX 宏,以及一个 per-project header 文件包含例如#define VRC_FILEDESC "Project Foo",那些 header 使用 ReadLinesFromFile/WriteLinesToFile 任务合并。无论如何,我的想法是最终得到一个 header 文件,例如
#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 1 $([System.DateTime]::Now.ToString(`yyyy`)) /fo $(VersionResourceOut) $(MsBuildThisFileDirectory)version.rc
注意
MakeSameWriteTime
将 .res 文件的修改时间设置为与输出文件相同的技巧,以确保预构建事件不会在每次.res 文件生成。可能有更好的方法来做到这一点,但这个对我有用:<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