Jep*_*sen 5 versioning git visual-studio
我正在使用visual studio 2013和git开发一个项目.
我必须分发项目的一些库,所以我想用当前的git commit hash设置它们的版本号,所以我可以确定它们正在使用哪个库版本.
有没有办法以自动方式将哈希作为版本号,即使用预构建事件,而不是每次都手动执行?
以下是使用资源文件的本机项目的可能实现的一些片段。这个想法是向项目添加一个属性表,该项目有一个预构建事件,该事件基于 git 提交哈希创建一个 .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>
Run Code Online (Sandbox Code Playgroud)
$(BuildToolsDir)tools\versionrc.targets 文件是实际创建资源文件的位置。完整的实现相当冗长,因为它也适用于 svn 并允许进行大量自定义 - 在这里发布的内容有点多,所以我只列出它的主要内容:
提交哈希存储在 msbuild 属性中,获取它的命令是
git --work-tree=$(GitVersionDir) --git-dir=$(GitVersionDir)\.git rev-parse --short HEAD
Run Code Online (Sandbox Code Playgroud)
其中 $(GitVersionDir) 通常设置为 $(MsbuildProjectDirectory),因为我们在源根目录中拥有大多数 .vcxproj 文件。
我还喜欢包含构建日期,因此最终进入 StringFileinfo 块的 FileDescription 条目的属性是
<FileDesc>$(GitVersion) $([System.DateTime]::Now.ToString('HH:mm:ss dd/MM/yyyy'))</FileDesc>
Run Code Online (Sandbox Code Playgroud)实际的文件/产品版本、公司名称和其他字段是从其他地方获取的。通常我们有一个公共头文件,定义 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
Run Code Online (Sandbox Code Playgroud)
whos 路径存储在 $(VersionMainIninclude) 属性中。
所有这些都用于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
Run Code Online (Sandbox Code Playgroud)请注意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>
Run Code Online (Sandbox Code Playgroud)这是使用的完整 .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
Run Code Online (Sandbox Code Playgroud)