同步的企业文件版本






3.83/5 (4投票s)
自动化C++、C#和VB大型应用程序套件的文件版本更新。
引言 - 为什么还需要另一个版本计数器?
企业应用程序的正确安装需要精确的文件版本。对于大量的应用程序来说,这可能会变得相当复杂,而构建号的同步有助于降低这种复杂性。
通过在整个套件中同步构建号,可以使应用程序的构建号识别(用于功能跟踪、错误跟踪、客户补丁、QA测试等)变得可管理。
然而,手动同步大型应用程序套件中所有文件版本和产品版本可能是一项耗时且容易出错的任务。最好以自动化方式完成此操作,并尽可能减少故障点。当手动更改不可避免时,最好只在一个地方更改版本号。
互联网上存在许多优秀的单应用程序自动化版本升级解决方案,我无意重复这些。本操作指南专门针对通过自动化流程(例如,通过CruiseControl等工具执行的夜间构建)构建的大型C++、C#和VB应用程序套件。
注意:这是一篇初学者级别的文章。
如果我下面的解释显得有点学究气,请理解我正在努力使其相当彻底,以适应多种技能水平。我希望通过包含我实际执行这些步骤以使这个项目运行/工作的详细步骤,尽可能多地回答可能出现的问题。
我在这里概述的解决方案使用的开发工具是Visual Studio 2008。我用Visual Studio .NET 2003 也做过类似的事情,只有一些细微的差别。本文中的解决方案以三种语言实现:C++、C#和VB。
为了方便起见(并本着让所有技能水平的人生活更轻松的精神),本文顶部的VS 2003 zip文件中提供了第二个解决方案。有关两种解决方案之间细微差别的简要说明,请参阅zip文件中的 ReadmeVS2003.pdf。我希望能定期编辑本文,并在有时间和机会时添加其他VS版本。早期版本,如VS 6.0,当然只支持C++,可能也支持VB。
创建基础项目
在本演示中
- 我创建一个空白项目
- 我添加C#文件版本支持
- 我添加C++版本支持
- 我添加VB版本支持(hack),然后
- 我为编译过程添加了简单的批处理版本更新(为简单起见,用DOS实现)
第一步是创建一个空白项目。
创建C#版本支持和示例应用程序
版本支持作为C#库项目实现。
我的向导预先创建了一个存根的 Class1.cs。我们将重用它来实现我们的自动化C#版本。将图3中的 const String
添加到 Class1.cs。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyCSharpVersion
{
public class Class1
{
public const String MyCurrentVersionNumber = "1.2.3.4";
}
}
为了完整性起见,我们使用这个类来更新C#版本库本身的文件和产品版本。编辑库程序集信息中的代码。在VC Studio 2008中,您可以在“属性”下找到它。
注意:在此项目中,将有两个C#程序集信息文件,一个用于C#版本库,另一个用于使用它的示例C#应用程序。这是前者。
输入图5中的代码以在编译时访问版本号。
注意:您将只添加图5中的一行并编辑另一行。其余内容包含在内,以便您找到插入/编辑代码的位置。
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using MyCSharpVersion;
.
.
.
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion(MyCSharpVersion.Class1.MyCurrentVersionNumber)]
编译库项目,并在包含已编译DLL的文件夹中打开Windows文件资源管理器。您可能需要将视图更改为“详细信息”。右键单击“详细信息”视图中的列标题以显示两个新列。选择“更多...”。选中“文件版本”和“产品版本”复选框。
您的显示现在应该类似于图7。
警告:此处显示的文件版本不一定与您右键单击DLL并查看“版本”选项卡时获得的文件版本匹配。
正如我们在C++示例中应该看到的那样,文件资源管理器显示的文件版本是嵌入在二进制文件中的整数,而“属性”对话框显示的文件版本是字符串资源(也嵌入在二进制文件中)。另一方面,Windows文件资源管理器中显示的产品版本与“属性”对话框中显示的产品版本是相同的。
接下来,我们创建一个使用版本库项目的示例C#版本应用程序。
此应用程序也将有一个程序集信息文件。打开它并添加与第一个程序集信息文件相同的代码(参见图5)。这次的不同之处在于,您还需要在新的C#应用程序项目中添加对C#版本库的引用。
现在,编译项目并使用类似于图6和图7的技术查看新的C#示例应用程序可执行文件的文件和产品版本。
创建C++版本支持和示例应用程序
为了实现C++的版本控制,我们需要创建一组头文件和源文件。我们可以将此添加到我们在此演示的第一部分中创建的空白项目中。首先,我们需要一个包含宏的头文件,我们需要将版本信息合并到我们的资源文件中(如图19所示)。
将图12中的宏集插入到头文件中。
#ifndef STRINGER
#define STRINGER( x ) #x
#endif
#ifndef RESTRINGER
#define RESTRINGER( x ) STRINGER( x )
#endif
#define MY_BUILD_FILE_NUMBER( rel, svcpk, minver, build ) \
RESTRINGER(rel) "." RESTRINGER(minver) "." RESTRINGER(svcpk) "." \
RESTRINGER(build) "\0"
#define MY_BUILD_PROD_NUMBER( rel, svcpk, minver, build ) \
RESTRINGER(rel) "." RESTRINGER(minver) "." RESTRINGER(svcpk) "." \
RESTRINGER(build) "\0"
#include "MyVersionNumber.h"
为版本号本身添加一个头文件。
插入图14中版本号的代码。如果您更改这些名称,您还必须更改使用它们的资源文件中的名称(如图19所示)。
#define MY_RELEASE_NUMBER 5
#define MY_SERVICE_PACK_NUMBER 4
#define MY_MINOR_VERSION_NUMBER 3
#define MY_BUILD_NUMBER 210
为了使其在VC 2008下无错误编译,我们还需要一个虚拟源文件。
添加一些代码使其编译。如果您愿意,可以发挥创意。图16中有些东西会起作用。
void main()
{
return;
}
现在,我们需要添加将使用此头文件信息的C++应用程序。这次,为了多样性,我们将创建一个Win32应用程序。
编辑C++向导创建的资源文件。这通常具有 .rc 或 .rc2 扩展名。对于某些项目,VC向导不会创建资源文件。在这些情况下,您将不得不添加自己的资源文件。此处未显示添加您自己的资源文件的步骤。
以文本模式编辑您选择的资源文件。在这里,我选择编辑 WindowsApplication2.rc。
如果您选择的资源文件尚不包含 VS_VERSION_INFO
块,则需要添加一个;否则,只需编辑现有的 VS_VERSION_INFO
块。图18中代码的重要部分引用了文件版本和产品版本。总共有四行(包含“FILEVERSION
”、“PRODUCTVERSION
”、“FileVersion
”和“ProductVersion
”)。
#include "..\VersionTest\MyVersionHeader.h"
VS_VERSION_INFO VERSIONINFO
FILEVERSION MY_RELEASE_NUMBER,MY_SERVICE_PACK_NUMBER,
MY_MINOR_VERSION_NUMBER,MY_BUILD_NUMBER
PRODUCTVERSION MY_RELEASE_NUMBER,MY_SERVICE_PACK_NUMBER,
MY_MINOR_VERSION_NUMBER,MY_BUILD_NUMBER
FILEFLAGSMASK VS_FF_DEBUG
FILEFLAGS 0x0L
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_APP
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904B0" // concatenation of US-English, Unicode
BEGIN
VALUE "Comments", "Prototype Version Auto Info\0"
VALUE "CompanyName","My Company\0"
VALUE "FileDescription", "Version Prototype\0"
VALUE "FileVersion", MY_BUILD_FILE_NUMBER(MY_RELEASE_NUMBER,
MY_MINOR_VERSION_NUMBER,MY_SERVICE_PACK_NUMBER,MY_BUILD_NUMBER)
VALUE "InternalName", "Version Prototype\0"
VALUE "LegalCopyright","Copyright © My Company 2009\0"
VALUE "LegalTrademarks","My Trademark\0"
VALUE "OriginalFilename", "versionautoinfo.exe\0"
VALUE "PrivateBuild", "\0"
VALUE "ProductName", "Version Prototype\0"
VALUE "ProductVersion",
MY_BUILD_PROD_NUMBER(MY_RELEASE_NUMBER,
MY_MINOR_VERSION_NUMBER,MY_SERVICE_PACK_NUMBER,MY_BUILD_NUMBER)
VALUE "SpecialBuild", "\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200 // US-English, Unicode
END
END
在编译之前,将VersionTest项目文件夹添加到您的 #include
路径中。
现在,编译,并检查文件和产品版本,就像您在图6和7中所做的那样。
创建Visual Basic版本支持和示例应用程序
我对自动版本控制的VB支持(我怀疑)是一个hack,实际上,以一种诡异的方式,它看起来与C#解决方案非常相似。它涉及编辑程序集信息文件。我确信有一些关于违反VB程序集信息文本文件“墓穴”的可怕警告,但在软件开发方面,我倾向于非常务实,有点像牛仔...也许有一些VB大师(我肯定不是其中之一)可以对此提供更多信息并给出一些明智的建议。
所以!话虽如此,请自行承担使用此技术的风险!
就像我们为C#所做的那样,创建一个VB库项目。
在我创建的 Class1
类中,我们放入了常量字符串,非常类似于我们为C#所做的那样。
Public Class Class1
Public Const MyCurrentVersionNumber = "11.0.0.20"
End Class
这次,为了多样性,让我们添加一个VB Windows服务。
现在到了hack部分。关闭解决方案!然后,从“开始 + 运行”编辑VB库程序集信息,如下所示。
notepad C:\VersionTest\MyVisualBasicVersion\My Project\AssemblyInfo.vb
编辑您的库程序集信息文件中包含 AssemblyFileVersion
的行。
' You can specify all the values or you can default the Build and Revision Numbers
' by using the '*' as shown below:
' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("1.0.0.0")>
<Assembly: AssemblyFileVersion(Class1.MyCurrentVersionNumber)>
现在以类似的方式编辑VB服务程序集,但请注意此处的额外“Imports
”行。
notepad C:\VersionTest\WindowsService3\My Project\AssemblyInfo.vb
Imports System
Imports System.Reflection
Imports System.Runtime.InteropServices
Imports MyVisualBasicVersion
.
.
.
' You can specify all the values or you can default the Build and Revision Numbers
' by using the '*' as shown below:
' <Assembly: AssemblyVersion("1.0.*")>
<Assembly: AssemblyVersion("1.0.0.0")>
<Assembly: AssemblyFileVersion(Class1.MyCurrentVersionNumber)>
现在重新启动,并将库添加到您的Windows服务中。
编译,并检查VB文件和产品版本,就像您在图6和7中所做的那样。
自动化每次构建的版本更新
要在批处理环境中实现此功能,最后一步是将版本增量机制添加到构建过程中。这可以通过多种方式完成,例如Apache Ant、Cygwin bash脚本、AWK、Perl、Python或许多其他脚本和自动化实用程序。我的演示为了简单起见,使用了DOS批处理命令。
创建一个包含初始版本和构建号的“种子”版本控制文件。例如,使用 notepad.exe 创建一个名为 C:\VersionTest\BUILDINFO.TXT 的文件,并插入图29中的文本。
MAJORVERSION=2
MINORVERSION=3
SERVICEPACK=4
BUILDNUMBER=19
再次使用 notepad.exe 创建一个名为 MYBUILD.BAT 的批处理文件,并插入图30中的文本。
注意:在此演示中,假定此批处理文件和 BUILDINFO.TXT 版本信息文件已在 C:\VersionTest 中创建。
@ECHO ON
REM (DV) THIS HAS BEEN TESTED ON WINDOWS XP USING VS.NET-2003 AND VS-2008
CALL "C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat"
SET LOGNAME=MYBUILD.LOG
SET BUILDINFOFILE=BUILDINFO.TXT
SET BUILDDRIVE=C:
SET BUILDROOT=%BUILDDRIVE%\VersionTest
REM Yes, I did mean to use "VersionTest" again in CPPHEADER :)
SET CPPHEADER=%BUILDROOT%\VersionTest\MyVersionNumber.h
SET CSHARPCLASS=%BUILDROOT%\MyCSharpVersion\Class1.cs
SET VBCLASS=%BUILDROOT%\MyVisualBasicVersion\Class1.vb
SET MAJORVERSION=0
SET MINORVERSION=0
SET SERVICEPACK=0
SET BUILDNUMBER=0
%BUILDDRIVE%
CD %BUILDROOT%
FOR /F %%I IN (%BUILDINFOFILE%) DO SET %%I
ECHO MAJOR VERSION = %MAJORVERSION%
ECHO MINOR VERSION = %MINORVERSION%
ECHO SERVICE PACK = %SERVICEPACK%
ECHO BUILD NUMBER = %BUILDNUMBER%
SET /A BUILDNUMBER=%BUILDNUMBER% +1
ECHO NEW BUILD NUMBER = %BUILDNUMBER%
ECHO MAJORVERSION=%MAJORVERSION% > %BUILDINFOFILE%
ECHO MINORVERSION=%MINORVERSION% >> %BUILDINFOFILE%
ECHO SERVICEPACK=%SERVICEPACK% >> %BUILDINFOFILE%
ECHO BUILDNUMBER=%BUILDNUMBER% >> %BUILDINFOFILE%
ECHO #define MY_RELEASE_NUMBER %MAJORVERSION% > %CPPHEADER%
ECHO #define MY_MINOR_VERSION_NUMBER %MINORVERSION% >> %CPPHEADER%
ECHO #define MY_SERVICE_PACK_NUMBER %SERVICEPACK% >> %CPPHEADER%
ECHO #define MY_BUILD_NUMBER %BUILDNUMBER% >> %CPPHEADER%
ECHO using System; > %CSHARPCLASS%
ECHO using System.Collections.Generic; >> %CSHARPCLASS%
ECHO using System.Linq; >> %CSHARPCLASS%
ECHO using System.Text; >> %CSHARPCLASS%
ECHO namespace MyCSharpVersion >> %CSHARPCLASS%
ECHO { >> %CSHARPCLASS%
ECHO public class Class1 >> %CSHARPCLASS%
ECHO { >> %CSHARPCLASS%
ECHO public const String MyCurrentVersionNumber =
"%MAJORVERSION%.%MINORVERSION%.%SERVICEPACK%.%BUILDNUMBER%"; >> %CSHARPCLASS%
ECHO } >> %CSHARPCLASS%
ECHO } >> %CSHARPCLASS%
ECHO Public Class Class1 > %VBCLASS%
ECHO Public Const MyCurrentVersionNumber =
"%MAJORVERSION%.%MINORVERSION%.%SERVICEPACK%.%BUILDNUMBER%" >> %VBCLASS%
ECHO End Class >> %VBCLASS%
TYPE %BUILDINFOFILE%
TYPE %CSHARPCLASS%
TYPE %CPPHEADER%
TYPE %VBCLASS%
CALL devenv VersionTest.sln /clean Release /out %LOGNAME%
CALL devenv VersionTest.sln /build Release /out %LOGNAME%
此批处理文件使用最新的构建号更新版本信息控制文件,然后创建三个版本文件,一个用于C++项目,一个用于C#项目,一个用于VB项目。然后它使用 devenv 编译器构建项目。
警告:如果您的源代码控制修改了源代码文件的只读属性,您将需要添加命令来清除只读属性,然后才能写入您的C#和C++文件(例如, ATTRIB 命令),或者直接强制删除它们(即DEL /F)。
要运行此程序
C:\> CD VersionTest
C:\VersionTest\> MYBUILD.BAT
使用上面图6和图7中的方法检查文件版本。每次运行构建批处理文件时,您都应该看到构建版本里程表递增一个数字。
最终评论
与此项目的大部分内容一样,最后一步有许多其他实现方式。我建议您选择与您当前构建环境最兼容的方式。
此解决方案严格设计为批处理过程运行。在我的环境中,每次从VS IDE构建解决方案时更新构建号是不必要的(实际上是不希望的)。在同一代码/应用程序上进行并行开发时,尤其是在采用正式源代码控制的情况下,通常会如此。但是,其他环境可能要求每次运行构建时都滚动版本号。在决定是将构建增量作为预构建步骤(此处未显示)还是作为批处理过程时,请记住这些因素。
历史
- 2009年11月17日 - 添加了适用于VS 2003 .NET的工作示例。
- 2009年11月20日 - 将VB hack添加到了VS 2008和VS 2003 .NET中。