How to have an auto incrementing version number (Visual Studio)?
If you add an AssemblyInfo class to your project and amend the AssemblyVersion
attribute to end with an asterisk, for example:
[assembly: AssemblyVersion("2.10.*")]
Visual studio will increment the final number for you according to these rules (thanks galets, I had that completely wrong!)
To reference this version in code, so you can display it to the user, you use reflection
. For example,
Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
DateTime buildDate = new DateTime(2000, 1, 1)
.AddDays(version.Build).AddSeconds(version.Revision * 2);
string displayableVersion = $"{version} ({buildDate})";
Three important gotchas that you should know
From @ashes999:
It's also worth noting that if both AssemblyVersion
and AssemblyFileVersion
are specified, you won't see this on your .exe.
From @BrainSlugs83:
Setting only the 4th number to be *
can be bad, as the version won't always increment.
The 3rd number is the number of days since the year 2000, and the 4th number is the number of seconds since midnight (divided by 2) [IT IS NOT RANDOM]. So if you built the solution late in a day one day, and early in a day the next day, the later build would have an earlier version number. I recommend always using X.Y.*
instead of X.Y.Z.*
because your version number will ALWAYS increase this way.
Newer versions of Visual Studio give this error:
(this thread begun in 2009)
The specified version string contains wildcards, which are not compatible with determinism. Either remove wildcards from the version string, or disable determinism for this compilation.
See this SO answer which explains how to remove determinism (https://stackoverflow.com/a/58101474/1555612)
Can I automatically increment the file build version when using Visual Studio?
In visual Studio 2008, the following works.
Find the AssemblyInfo.cs file and find these 2 lines:
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
You could try changing this to:
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("1.0.*")]
But this won't give you the desired result, you will end up with a Product Version of 1.0.* and a File Version of 1.0.0.0. Not what you want!
However, if you remove the second of these lines and just have:
[assembly: AssemblyVersion("1.0.*")]
Then the compiler will set the File Version to be equal to the Product Version and you will get your desired result of an automatically increment product and file version which are in sync. E.g. 1.0.3266.92689
Auto increment FileVersion (build nr) in Visual Studio 2019
Does anyone have a better solution than this ?
Better, I don't know, different yes.
There is no actual need for a 3rd party tool. We use a simple script for doing this and it was running since I can remember (about Visual Studio 2010 I think, with some changes since back then). However, you need to fulfill some prerequisites (but which can come in handy). The script below should run in Visual Studio 2019/2017 and PowerShell 3+.
We have a file version.h
which looks like this:
#pragma once
#define VERSION_MAJOR 1
#define VERSION_MINOR 0
#define VERSION_PATCH 0
#define VERSION_BUILD 0
#define stringify(a) stringify_(a)
#define stringify_(a) #a
Note: version.h requires a new line at the end to avoid fatal error RC1004: unexpected end of file found
.
Resource files can include header files, and therefore include version.h
in your resource file and change it to use the defines accordingly:
#include "version.h"
// ... other stuff
VS_VERSION_INFO VERSIONINFO
FILEVERSION VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_BUILD
PRODUCTVERSION VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_BUILD
// ... other stuff
VALUE "FileVersion", stringify(VERSION_MAJOR) "." stringify(VERSION_MINOR) "." stringify(VERSION_PATCH) "." stringify(VERSION_BUILD)
VALUE "ProductVersion", stringify(VERSION_MAJOR) "." stringify(VERSION_MINOR) "." stringify(VERSION_PATCH) "." stringify(VERSION_BUILD)
// ... other stuff
Now in the project properties pre-build scripts we are running a PowerShell script. The command:
powershell.exe -ExecutionPolicy Bypass -NoProfile -NonInteractive -File update_version.ps1 "./version.h"
And the script is a find & replace text with an increment:
(Get-Content -path $args[0] -Raw) |
ForEach-Object {
$defstr="#define VERSION_BUILD ";
$regex="$defstr(?<BuildVersion>\d*)";
if($_ -match $regex) {
$_ = $_ -replace $regex,"$($defstr)$(([int]$matches["BuildVersion"])+1)"
}
$_
} |
Out-File $args[0] -encoding ascii -nonewline
Some advantages are:
version.h
is plain C and can be parsed by any C/C++-compliant compiler, MSVC resource compiler or even tools like Doxygen.- You can use it in your C++ files:
#include "version.h"
int main() {
std::cout << "Hello World Version " stringify(VERSION_MAJOR) "." stringify(VERSION_MINOR) "." stringify(VERSION_PATCH) "." stringify(VERSION_BUILD) " !\n";
}
- versioning is centralized
- other scripts to handle major/minor/patch versions are also simple
- the scripts are fairly simple, and maintenance is also simple
How to auto increment the version (eg. “1.0.*”) of a .NET Core project?
One simple way I did it previously is reading the current version and increase it by one, so you get current version and increment by one using command line.
I found this article would answers your question: https://sachabarbs.wordpress.com/2020/02/23/net-core-standard-auto-incrementing-versioning/
Auto-increment version revision number with wildcard
I found this:
https://marketplace.visualstudio.com/items?itemName=PrecisionInfinity.AutomaticVersions
It's hilarious that VS doesn't have this built-in.
MSBuild auto increment build version differently for release/debug
MSBuild auto increment build version differently for release/debug
In general, MSBuild did not have a function to see the version number of the obvious incremental build but only used the timestamp of the system build determines the build order as you used before.
In fact, if you create a custom property in msbuild to record the version number of the incremental build, it still needs to use an entity to store the record, and if it is not used, the parameter is reinitialized for each build (the msbuild attribute can only be identified in msbuild).
So the ideal way it that use textfile as an intermediate. You can follow my solution:
Solution
1) create a custom msbuild task which does increment the value of the record property.
--a) Create a class library project called MyCustomTask
then Right-click on the project-->Add Reference-->reference Microsoft.Build.Framework
dll and Microsoft.Build.Utilities.v4.0
dll.
--b) add these into CustomTask.cs
(this is the name of the task which will be used in xxx.csproj
file).
public class CustomTask : Task
{
private int _number;
[Required]
public int number //input taskitem
{
get { return _number; }
set { _number = value; }
}
private int _lastnumber;
[Output]
public int LastNumber //output value
{
get { return _lastnumber; }
set { _lastnumber = value; }
}
public override bool Execute() // Execution logic
{
LastNumber = number + 1;
return true;
}
}
--c) Then build the project and remember to store its MyCustomTask
dll.
2) Aim to your main project and then create two txt files called Debug.txt
,Release.txt
and give each of them an initial value of 0
.
3) add these into your Directory.Build.props
file:
<Project>
<UsingTask TaskName="CustomTask" AssemblyFile="xxxxxx\MyCustomTask\MyCustomTask\MyCustomTask\bin\Debug\MyCustomTask.dll(the local path of the dll)"> </UsingTask>
<PropertyGroup>
<Record></Record>
</PropertyGroup>
<Target Name="WriteToFile1" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<Record Condition="'$(Configuration)'=='Debug' and !Exists('$(TargetPath)')">
0
</Record>
<Record Condition="'$(Configuration)'=='Release'and !Exists('$(TargetPath)')">
0
</Record>
</PropertyGroup>
<ItemGroup Condition="'$(Configuration)'=='Debug'">
<MyTextFile Include="Debug.txt">
<Number>$(Record)</Number>
</MyTextFile>
</ItemGroup>
<ItemGroup Condition="'$(Configuration)'=='Release'">
<MyTextFile Include="Release.txt">
<Number>$(Record)</Number>
</MyTextFile>
</ItemGroup>
<WriteLinesToFile
File="@(MyTextFile)"
Lines="$(Record)"
Overwrite="true"
Encoding="Unicode" Condition="'$(Configuration)'=='Debug'"/>
<WriteLinesToFile
File="@(MyTextFile)"
Lines="$(Record)"
Overwrite="true"
Encoding="Unicode" Condition="'$(Configuration)'=='Release'"/>
<PropertyGroup>
<Version>
$([System.DateTime]::Now.Year).
$([System.DateTime]::Now.Month).
$([System.DateTime]::Now.Day).
$(Record)
</Version>
</PropertyGroup>
</Target>
<Target Name="ReadLineFromFile" BeforeTargets="WriteToFile1">
<ReadLinesFromFile File="Debug.txt" Condition="'$(Configuration)'=='Debug'">
<Output TaskParameter="Lines" PropertyName="Record"/>
</ReadLinesFromFile>
<ReadLinesFromFile File="Release.txt" Condition="'$(Configuration)'=='Release'">
<Output TaskParameter="Lines" PropertyName="Record"/>
</ReadLinesFromFile>
<CustomTask number="$(Record)">
<Output TaskParameter="LastNumber" PropertyName="Record"/>
</CustomTask>
</Target>
</Project>
4) When you execute a task which depends on Build to show the property Version
, it will work well as you hope.
Note that it will work for incremental build and if you click Rebuild
(which execute Clean and then Build), it will set the version number to zero and start the rethrow.
Overall, this is an ideal solution which I try to realize it.
Related Topics
Difference Between a Regular String and a Verbatim String
Serialport Not Receiving Any Data
Multiline String Literal in C#
Split a String by Another String in C#
How to Make a Winforms App Go Full Screen
How to Associate a File Extension to the Current Executable in C#
Ef Core Returns Null Relations Until Direct Access
Line Delimited Json Serializing and De-Serializing
Get String Between Two Strings in a String
Ipc Mechanisms in C# - Usage and Best Practices
What Does "Use of Unassigned Local Variable" Mean
Cast Generic≪Derived≫ to Generic≪Base≫
How to Update the Current Line in a C# Windows Console App