VC2005利用SVN的版本号,生成DLL和EXE文件的版本号
TortoiseSVN下有一个SubWCRev程序,可以获取任意个路径对应的SVN版本库的版本号。并替换到文件对应位置。
VC2005的资源文件可以控制生成的二进制文件版本号。
可以利用VC2005的生成前命令,调用SubWCRev来获取最新的SVN版本号并写入生成的二进制文件中。
程序也可以判断调用的DLL版本号是否比本身大。以控制不会调用不对应的动态库。可以使依赖多了一层运行时保证。
实现该目的,需要
- 每次编译前,从svn获取当前版本库的版本号,并写入资源文件
- 编译完成后,打安装包时,读取版本信息
需要注意两点:
1,svn的工具可获取版本号并更新到项目文件
如果提供了源文件和目的文件,SubWCRev 会复制源文件到目标文件,执行如下所属的关键字替换:
表 5.2. 列出可用的命令行开关
关键字 | 描述 |
---|---|
$WCREV$ | 用工作副本中最高的提交版本来替换 |
$WCDATE$ | 用最高提交版本的日期/时间替换。默认使用国际化格式:yyyy-mm-dd hh:mm:ss 。作为选择,你可以指定strftime() 使用自定义格式,例如:$WCDATE=%a %b %d %I:%M:%S %p$ 。格式字符的列表参见在线引用。 |
$WCNOW$ | Replaced with the current system date/time. This can be used to indicate the build time. Time formatting can be used as described for$WCDATE$ . |
$WCRANGE$ | 在工作目录用更新版本范围替换。如果工作目录处于一致的状态,它是一个单一版本。如果工作目录包含混合版本,或者是过时,或者是故意更新到版本,那么这个范围会用象100:200这样的格式来显示。 |
$WCMIXED$ | 当有混合版本时用TText 替换$WCMIXED?TText:FText$ ,否则用FText 替换。 |
$WCMODS$ | 若本地存在修改,就用TText 替换$WCMODS?TText:FText$ ,否则用FText 替换。 |
$WCURL$ | 用传递给SubWCRev的工作目录的版本库地址替换。 |
$WCINSVN$ | $WCINSVN?TText:FText$ is replaced withTText if the entry is versioned, orFText if not. |
$WCNEEDSLOCK$ | $WCNEEDSLOCK?TText:FText$ is replaced withTText if the entry has thesvn:needs-lock property set, orFText if not. |
$WCISLOCKED$ | $WCISLOCKED?TText:FText$ is replaced withTText if the entry is locked, orFText if not. |
$WCLOCKDATE$ | Replaced with the lock date. Time formatting can be used as described for$WCDATE$ . |
$WCLOCKOWNER$ | Replaced with the name of the lock owner. |
$WCLOCKCOMMENT$ | Replaced with the comment of the lock. |
下面的例子显示了模版文件中的关键字是如何在输出文件中被替换的。
// Test file for SubWCRev: testfile.tmpl char *Revision = "$WCREV$"; char *Modified = "$WCMODS?Modified:Not modified$"; char *Date = "$WCDATE$"; char *Range = "$WCRANGE$"; char *Mixed = "$WCMIXED?Mixed revision WC:Not mixed$"; char *URL = "$WCURL$"; #if $WCMODS?1:0$ #error Source is modified #endif // End of file
After runningSubWCRev.exe path\to\workingcopy testfile.tmpl testfile.txt
, the output filetestfile.txt
would looks like this:
// Test file for SubWCRev: testfile.txt char *Revision = "3701"; char *Modified = "Modified"; char *Date = "2005/06/15 11:15:12"; char *Range = "3699:3701"; char *Mixed = "Mixed revision WC"; char *URL = "http://project.domain.org/svn/trunk/src"; #if 1 #error Source is modified #endif // End of file
SubWCRev.exe从命令行或脚本中运行,使用命令行参数控制。
SubWCRev WorkingCopyPath [SrcVersionFile DstVersionFile] [-nmdfe]
WorkingCopyPath
是要检查的工作副本路径,你可以只对工作副本使用SubWCRev,而不是直接对版本库,这个路径可以是绝对路径,也可以是工作目录的相对路径。
如果你想让SubWCRev执行关键字替换,象版本库版本,地址等字段保存到文本文件,就需要提供一个模版文件SrcVersionFile
,输出文件DstVersionFile
就是模版替换之后的版本。
有几个开关影响 SubWCRev工作。如果使用多个,必须用单个组指定,例如要用-nm
,不能用-n -m
。
表 5.1. 列出可用的命令行开关
切换 | 描述 |
---|---|
-n | If this switch is given, SubWCRev will exit withERRORLEVEL 7 if the working copy contains local modifications. This may be used to prevent building with uncommitted changes present. |
-m | If this switch is given, SubWCRev will exit withERRORLEVEL 8 if the working copy contains mixed revisions. This may be used to prevent building with a partially updated working copy. |
-d | If this switch is given, SubWCRev will exit withERRORLEVEL 9 if the destination file already exists. |
-f | 如果给出这个开关,SubWCRev 就会包含文件夹的最后修改版本。默认行为是取得版本号时只考虑文件。 |
-e | If this switch is given, SubWCRev will examine directories which are included withsvn:externals , but only if they are from the same repository. The default behaviour is to ignore externals. |
-x | If this switch is given, SubWCRev will output the revision numbers in HEX. |
-X | If this switch is given, SubWCRev will output the revision numbers in HEX, with ‘0X‘ prepended. |
参考这个文档http://tortoisesvn.net/docs/nightly/TortoiseSVN_zh_CN/tsvn-subwcrev.html
2,每次编译版本前执行一次获取版本号操作
以 vc6 为例, 文件的版本信息保存在 rc 文件. 编译成 res 文件, 然后和其他 obj 一起 link. 现在的思路就是. 编辑 rc 文件, 将版本号比如 2.2.4.0 改成 2.2.4.$WCREV$, 在每次 link 之前, 先用 subwcrev.exe 处理 rc 文件, 进行宏替换. 然后调用 rc.exe 编译替换后的新文件. 生成 res 之后一起 link.
. 修改 rc 文件的 versioninfo 段成如下:
#ifdef _AUTOVERSION
FILEVERSION 2,2,4,$WCREV$
PRODUCTVERSION 2,2,4,$WCREV$
#else
FILEVERSION 2,2,4,0
PRODUCTVERSION 2,2,4,0
#endif
...
#ifdef _AUTOVERSION
VALUE "FileVersion", "2, 2, 4, $WCREV$\0"
VALUE "ProductVersion", "2, 2, 4, $WCREV$\0"
#else
VALUE "FileVersion", "2, 2, 4, 0\0"
VALUE "ProductVersion", "2, 2, 4, 0\0"
#endif
其实也就是加上了条件编译. 默认情况下没有定义 _AUTOVERSION, 则使用原来的 fileversion, productversion. 如果定义了 _AUTOVERSION, 则使用新的版本信息.
. 在项目属性找到 pre-link 页. 在其中增加:
subwcrev\subwcrev.exe . myprogram.rc myprogram.rc_
rc.exe /l 0x804 /fo"\release\myprogram.res" /d "_AUTOVERSION" /d "_AFXDLL" "myprogram.rc_"
第一条命令处理 myprogram.rc , 生成 myprogram.rc_
第二条命令编译 myprogram.rc_ 为 myprogram.res, 注意它的路径. 这里是 release 版的默认路径. 原则就是这里生成的 res 替换原来的 res 文件.
按 f7, build. 现在版本信息已经刷新了. 每次向 svn 提交. 版本都会更新.
不过我们还可以更进一步. 将版本信息, 编译时间等写入到关于对话框中. 其实关键还是 pre-link.
. 创建一个文件 buildtime.cpp, 内容如下:
const char*szBuildTime = "Build on $WCNOW$";
const char*szFullVersion="MyProgram 2.2.4.$WCREV$$WCMODS?+:$$WCMIXED?#:$";
. 在关于对话框 OnInitDialog() 中加入:
extern const char* szBuildTime;
extern const char* szFullVersion;
SetDlgItemText(IDC_BUILDTIME, szBuildTime);
SetDlgItemText(IDC_VERSION, szFullVersion);
. 在 pre-link 再加上两条:
subwcrev\subwcrev.exe . buildtime.cpp buildtime_.cpp
cl /c /nologo /Fo\Release\buildtime.obj /MT buildTime_.cpp
原理和 rc 文件一样. 先替换, 后编译. 同样要保证生成的 buildtime.obj 覆盖原来的 buildtime.obj
大功告成.
不过有一点要注意. vc6 的资源编辑器在每次编辑资源之后都重新生成 rc 文件. 也就是说, 会删除我们对 rc 的修改. 还没有找到好的办法, 现在只能是每次编辑资源之后再手工添加一下条件编译的部分. 建议在项目进入 beta 之后再加上版本信息. 因为这个时候程序的资源一般都不会变动了.
另外, 虽然这里是以 vc6 为例, 但也可以应用到 vc2003, vc2005 等编译环境.
后记: 还可以考虑用程序自动修改. 找到 FILEVERSION, 将后面的版本替换成 FILEVERSION 2,2,4,$WCREV$, 然后再用 subwcrev 替换. 再用 rc 编译. 这样还不用定义 _AUTOVERSION 宏