Foreword
之前写过一篇,C++ CLI/CLR下的版本号自增,最近又探索了一下,发现了一些新的方式,也比较简单方便。
http://elmagnifico.tech/2021/06/01/CLR-Auto-Version-Increase/
TextTemplate
TextTemplate的语法教程相关,看官方文档
https://docs.microsoft.com/en-us/visualstudio/modeling/writing-a-t4-text-template?view=vs-2022
简单说在C#工程中增加一个文本模板,后缀是tt的文件
然后输入下面的内容
<#@ template language="C#" #>
//
// This code was generated by a tool. Any changes made manually will be lost
// the next time this code is regenerated.
//
using System.Reflection;
[assembly: AssemblyVersion("1.0.1.<#= this.RevisionNumber #>")]
[assembly: AssemblyFileVersion("1.0.1.<#= this.RevisionNumber #>")]
<#+
int RevisionNumber = (int)(DateTime.UtcNow - new DateTime(2010,1,1)).TotalDays;
#>
大致解释一下,文件模板,就是当你任何修改保存或者编译的时候,工程会自动执行文件模板。上述的模板就会生成一个C#的同名.cs文件,这个文件在tt模板的下面,其内容其实就是一个标准的cs的文件,只是RevisionNumber的值,每次会自动计算更新并存入文件中。
这样版本号的末尾就变成了utc时间距2010年1月1日所经过的日子了
通过这种方式就巧妙的实现了AssemblyVersion
和AssemblyFileVersion
的自动更新,并且规则可以自己定义
- 版本号的模式必须是x.x.x.x,否则系统会自动给你补0上去
下面这个模板则是自动生成1.年.1月日.1十分
格式的版本号
<#@ template language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
//
// This code was generated by a tool. Any changes made manually will be lost
// the next time this code is regenerated.
//
using System.Reflection;
<#
var date = DateTime.Now;
int major = 1;
int minor = date.Year;
int build = 10000 + int.Parse(date.ToString("MMdd"));
int revision = 10000 + int.Parse(date.ToString("HHmm"));
#>
[assembly: AssemblyVersion("<#= $"{major}.{minor}.{build}.{revision}" #>")]
[assembly: AssemblyFileVersion("<#= $"{major}.{minor}.{build}.{revision}" #>")]
这个模板稍微特殊一点,他是通过反向读取cs中的内容,来进行更新的,当然这里不会死锁。
<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#
string output = File.ReadAllText(this.Host.ResolvePath("AssemblyInfo.cs"));
Regex pattern = new Regex("AssemblyVersion\\(\"(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<revision>\\d+)\\.(?<build>\\d+)\"\\)");
MatchCollection matches = pattern.Matches(output);
if( matches.Count == 1 )
{
major = Convert.ToInt32(matches[0].Groups["major"].Value);
minor = Convert.ToInt32(matches[0].Groups["minor"].Value);
build = Convert.ToInt32(matches[0].Groups["build"].Value) + 1;
revision = Convert.ToInt32(matches[0].Groups["revision"].Value);
if( this.Host.ResolveParameterValue("-","-","BuildConfiguration") == "Release" )
revision++;
}
#>
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Resources;
// General Information
[assembly: AssemblyTitle("DCTracker")]
[assembly: AssemblyDescription("Diablo Clone Tracker")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("elmagnifico")]
[assembly: AssemblyProduct("DCTracker")]
[assembly: AssemblyCopyright("opyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Version Information
[assembly: AssemblyVersion("<#= this.major #>.<#= this.minor #>.<#= this.revision #>.<#= this.build #>")]
[assembly: AssemblyFileVersion("<#= this.major #>.<#= this.minor #>.<#= this.revision #>.<#= this.build #>")]
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]
<#+
int major = 1;
int minor = 0;
int revision = 0;
int build = 0;
#>
- 需要注意这个模板的major、minor、revision的修改,需要修改对应的cs,而build是自动的,其他模板修改可能是直接修改tt文件就行了
他生成的模板就像下面一样
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Resources;
// General Information
[assembly: AssemblyTitle("DCTracker")]
[assembly: AssemblyDescription("Diablo Clone Tracker")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("elmagnifico")]
[assembly: AssemblyProduct("DCTracker")]
[assembly: AssemblyCopyright("opyright © 2022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Version Information
[assembly: AssemblyVersion("1.2.1.20")]
[assembly: AssemblyFileVersion("1.2.1.20")]
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]
Summary
VS的版本号的设计着实有些死板,想自己定义成自己想要的方式都不行,也太蠢了
Textemplate的模式,不限于C#,只要是MSbuild其实都可以使用,他是在编译过程中作为一个辅助工具一样的,被调用而已,所以C++或者是其他的工程只要在VS里基本都可以使用。
Quote
https://stackoverflow.com/questions/356543/can-i-automatically-increment-the-file-build-version-when-using-visual-studio
https://stackoverflow.com/questions/826777/how-to-have-an-auto-incrementing-version-number-visual-studio
http://www.cppblog.com/diryboy/archive/2010/08/17/VS2010AddT4InCppProject.html
https://docs.microsoft.com/en-us/visualstudio/modeling/design-time-code-generation-by-using-t4-text-templates?view=vs-2022
https://docs.microsoft.com/en-us/visualstudio/modeling/code-generation-and-t4-text-templates?view=vs-2022