65.9K
CodeProject 正在变化。 阅读更多。
Home

构建计数自动递增

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.90/5 (9投票s)

2000年5月17日

viewsIcon

145834

downloadIcon

919

了解如何为您的项目实现自动递增的构建编号。

  • 下载源文件 - 33 Kb

    问题

    在执行构建时,让构建编号(版本号的低 16 位)自动递增会很有用。这有助于您跟踪发行版本。然而,Microsoft 在构建系统中并未提供任何机制来实现这一点。因此,出现了许多解决方案,但出于我将在后面讨论的各种原因,我都觉得它们不令人满意。我的不满最终促使我启动了一个新的主要项目,并编写了自己的解决方案。它也有问题。但是,它遇到的问题是我认为比其他解决方案更可接受的一组问题。您可能喜欢或不喜欢这个解决方案,这取决于您。


    先前的解决方案

    我的第一个解决方案(已废弃)

    以前,我有一个自动版本步进器,作为我手工制作的 makefile 的一部分运行。它运行一个名为“version”的小程序,该程序读取一个名为 version.h 的文件,递增句点后面的版本号,然后将文件写回。然后我就可以任意使用这个版本号字符串。它还写入一个名为 version.ver 的伴随文件,该文件由我的编辑器用于将版本号插入更改日志。这已经运行了很多年。唯一的缺点是依赖于 version.h 的文件会在每次构建时重新编译,所以我通常会把它做成一个小的文件,只包含一个子程序中的 sprintf

    version.h:
    #define VERSION_NUMBER "1.361"
    

    然后出现了 Visual C++。好消息是,自从我开始使用它以来,我就不必查看 makefile 的内部了。坏消息是,直到最新版本发布之前,都没有有效的方法来添加自定义构建步骤。我不得不手动运行我的“version”小程序。现在有机会添加一个自动步骤。但是这个步骤里该放什么呢?


    修补可执行文件

    我首先去了新的、改进的LCodeGuru 网站。我在那里搜索解决方案。其中一个解决方案是一个程序,它进入可执行文件并重写 VERSIONINFO 资源。我对此感到风险很大,而且关于它的补充评论,例如未能重新计算校验和导致的问题,使我放弃了它。此外,我早在多年前就做过这件事(而且我确实重新计算了校验和),而且我认为这是一种相当脆弱的机制(在 cited 示例中,我是在安装过程中将许可证信息写入可执行文件,包括一个加密的密码)。所以,我把它排除了,尽管它在理论上是最优雅的机制,因为它不会强制重新编译或重新加载资源。


    VBA 子程序

    另一种机制是一个 VBA 子程序,它可以由编译机制自动调用。它会将资源文件读取为文本,进行更改,然后写回。它有一些报告的问题和修复,但它有一个问题,即每次构建(无论成功与否)都会递增数字。它还有一个问题,就是它会关闭资源文件,然后将其作为文本文件重新加载,修改它,然后写出。然后它会删除资源文件的文本版本。如果您采用我的解决方案并修改 .rc 文件,效果虽然通过不同的方式获得,但会相同。但我有一个解决办法。


    插件

    另一个解决方案是一个 VC++ 插件。这看起来非常酷,但遗憾的是,它没有附带任何源代码,只有一个 DLL 文件。所以我决定跳过它。如果附带源代码,我可能会考虑它。

    然后我考虑自己做一个插件。对插件文档的简要浏览让我确信,尽管听起来很吸引人,但这超出了我的工作量门槛。由于这个工具的工作量“已超标”,它不会产生任何收入,而且由于我还有一些截止日期要赶,我也无法花费我应该花费的时间来开发它。


    我自己的解决方案

    在排除了各种现有的解决方案之后,我决定自己做一个。这是我获得所需解决方案的唯一方法。这是一个作为预链接步骤运行的程序。

    这里的问题是,如果我修改 .rc 文件,那么 .res 文件将比 .rc 文件旧,这将强制重新构建,同时 VC++ 会不断提示我需要重新构建文件才能运行。当然,我每次都可以选择“否”,但这会增加出错的可能性,因为我没有仔细阅读实际内容。所以我想以一种不会触发这种虚假重新构建或消息的方式来做。

    该程序名为 buildinc。将可执行文件放在您为此目的保留的有用工具目录中,或在其自己的目录中构建它。它接受两个命令行参数,一个 version.ver 文件的名称和一个包含 VERSIONINFO 结构的 .rc 文件的名称。精确地两个参数,按此精确顺序。

    如果 version.ver 文件不存在,将创建一个。初始版本值设置为

       1, 0, 0, 0
    

    因此,如果您在当前 .rc 文件上运行此命令,版本将重置。记下您想要的版本,然后手动编辑 version.ver 来更改该值。

    version.ver 文件的语法是形如

    verno\tyyyy mm dd hh:mm:ss (www mmm-dd)
    

    的行的序列,其中 verno 可以有以下两种形式之一

    num, num, num, num
    

    num.num.num.num
    

    请注意,空格是可选的,但不会被保留。如果版本号只包含逗号,它将被重新生成为上面的逗号形式,即逗号后面有空格;如果它包含任何句点,它将被重新生成为没有空格的句点形式。

    请注意,如果您为二进制文件版本号输入 16.14.2.1234 这样的数字,资源编译器似乎能够解析它并存储正确的值。因此,我没有努力为文件版本字符串表示使用一种形式,为二进制版本使用另一种格式。

    我的程序会扫描 .rc 文件,查找形如

    FILEVERSION anything
    

    的行,并将其替换为

    FILEVERSION newversion
    

    以及形如

    VALUE "FileVersion"
    

    的行,并将其替换为

    VALUE "FileVersion", "newversion\0"
    

    如果您在文件中拥有多个资源(本地化),它将找到后者并为所有支持的语言进行替换。但是,在此版本中,我不支持多个输入文件,所以如果您需要此支持,则需要重写程序以接受多个输入文件。

    为什么我使用 version.ver 作为版本号的最终来源,而不是资源文件?因为我想要两个功能:一个持续的版本生成日期日志,以及我的编辑器能够读取 version.ver 文件并向更改日志条目添加当前版本号。另外,因为我实际上将 VERSIONINFO 资源移到了 .rc2 文件中,这意味着我只需要编辑一个文本文件就可以手动更改版本号,例如,更改前三个字段中的任何一个。

    创建了新的版本号后,程序将修改 .rc 文件。由于我对这类事情有些偏执,并且基于其他工具收到的各种错误报告,我决定使用以下算法:

    1. 获取构建号,并根据 .rc 文件和构建号创建一个文件名,例如,如果构建号是 202,而 .rc 文件是 myproject.rc,我将生成文件名 myproject.rc.0202
    2. 将构建号减去 10,并删除任何具有该名称的文件,因此在上面的示例中,我将删除文件名 myproject.rc.0192。这可以防止空间变得过于拥挤,但会给我留下一定数量的备份副本。
    3. 将当前 .rc 文件重命名为该文件名。
    4. 读取该文件,并创建一个新的 .rc 文件,其中包含更新的构建号。

    然后,我创建了项目“myproject”的预链接构建步骤

    buildinc-path\buildinc.exe version.ver myproject.rc
    

    这只是完成了一半的工作。然后我转到“Resources”选项卡,选中那里的命令行,并将其复制。然后我创建了*第二个*预链接步骤,

    rc pasted-commands-here myproject.rc
    

    这强制重新编译我刚刚更改的资源文件,这样我就不会收到任何虚假的重新构建通知,也不会陷入无限的重新构建循环。

    下面是调试设置的显示。某些区域已留空以保护专有信息。您必须记住为调试设置和发布设置执行此操作,当然也要为任何自定义设置执行此操作。不要忘记将第二个步骤中的目录更改为指向正确的目录(如果您从一个自定义预链接步骤复制粘贴到另一个,您可能会忘记更改这一点)。


    缺点

    我使用 version.ver 文件作为版本号的最终表示,而不是 VERSIONINFO 资源。更改它只是一个小重写,但我决定这是我想要的解决方案。当然,由于您拥有源代码,如果您不喜欢这个解决方案,可以轻松地重写它。

    它还需要在预链接步骤中手动重新构建 .rc 文件,这意味着如果我需要更改包含路径或以其他方式修改 rc 编译步骤的行为,我必须记住不仅在“Resources”选项卡中进行更改,还要在我的预链接步骤中进行更改。在我使用 VC++ 的这五年里,我从未修改过“Resources”构建,所以我认为这不会困扰我。您的实际情况可能不同。

    它在外部修改 .rc 文件,这会在每次成功构建后强制重新加载。我认为这是我所做的事情中最大的一个缺点。您可能会觉得它尚可接受,或者会憎恨它。一种解决方法(我已采用)是将 VERSIONINFO 资源移到 res\project.rc2 文件中,并将 .rc2 文件指定为 buildinc 的目标文件。这意味着您无法在资源编辑器中编辑 VERSIONINFO 文件,但这可能不是问题,因为我实际编辑它的次数(除了更改版本号之外)如此之少,以至于足以弥补我无需每次都重新加载资源的便利。

    我将此构建为 MFC 控制台应用程序。这是因为我懒惰。我想要 CString,但我需要一个控制台应用程序。同样,我决定上周末学习 STL 不是我想要的,所以我只使用了 MFC。如果您想使用 STL 重写此程序,请随意。如果您将副本发给我,我甚至会将其发布给其他人(请在源代码中包含您想要的任何署名信息……)。


    更改日志

    更改日志对我来说非常重要。我有数百个项目,其中相当一部分是出售给其他人的,他们为之付了钱。我需要维护更改日志来保持我的理智(后者是主要的维护问题,尽管许多人认为这种维护已经完全失败)。多年前,特别是 1985 年 8 月 8 日(根据我的更改日志程序的更改日志),我创建了一种快速、高效的方法来处理这个问题。我使用 Lugaru 的 Epsilon 文本编辑器(Lugaru)。

    我对 VC++ 编辑器的看法是,它是一个勉强可接受的初步尝试,但距离我愿意长期使用还有很长的路要走。它混淆了一些基本概念,如“窗口”和“视口”,而且它不是一个对键盘友好的编辑器。我打字速度可以达到 70 wpm,我讨厌为了使用鼠标而打断打字速度。我已经使用 EMACS 类编辑器超过 25 年了,它们似乎很适合基于键盘的编辑任务,而我也很熟悉它们。

    通过一种按键组合,我可以安装一个更改日志;通过另一种,我可以添加一个条目。自动换行是自动的。我有一些工具可以处理更改日志,按更改号合并更改,并总结我添加的更改行数。我有一个单独的按键组合,可以将更改请求号插入到受更改影响的行上。这是在我一个应用程序中创建的更改日志

    /*****************************************************************************
    * Change Log
    * Date      | Change
    *-----------+-----------------------------------------------------------------
    * 13-Jan-99 | Created change log
    * 13-Mar-00 | [2.0.0.6] REQ #127: Changed base string to use default language ID
    *****************************************************************************/
    

    注意 [string] 是通过读取 version.ver 文件的第一行添加的。REQ #127 表示更改是修改请求的结果,具体是请求 127。这是由另一个键盘按键请求添加的。因此,我知道更改添加到的构建级别。虽然中间构建不太重要,但这与一个尚未编写的 awk 脚本一起,将允许我向客户提供适用于每个发行版本的更改列表。这使得跟踪版本以便于客户支持更容易。它还清楚地表明了哪些发行构建包含哪些更改请求(更改请求由客户发送给我;我分配一个更改号并将更新后的更改号文件发回)。

    当前的 awk 脚本通过生成按文件名列出的更改行摘要列表以及总行数来跟踪更改,例如

    ----------------------------------------------------------------------------
    REQ #133 | (11)
    ---------+
    ./.\crosspnt.c: * 20-Dec-99 | [1.387] REQ #133: Handle Delete key 
    ./.\FLTRDLG.C: * 22-Dec-99 | [1.387] REQ #133: Fixed display bug for console format
    ----------------------------------------------------------------------------
    

    这告诉我更改请求 #133 涉及两个文件,crosspnt.cFLTRDLG.C,以及日期和更改。由于这早于我的新 buildinc 应用程序,它使用了旧的 version.build 显示。它涉及 11 行更改。

    在分析所有文件后,我还获得了摘要报告

    ----------------------------------------------------------------------------
    Total REQs 210
    Change lines 24446
    Total source lines 133481
    Total files 690
    ----------------------------------------------------------------------------
    

    在本项目五年的生命周期中,从 1997 年的初始产品发布到现在,共有 24446 行源代码更改或添加,这代表了通常的维护活动,如错误修复和功能添加。为该产品添加 Internet 支持实际上占了大约 11,000 行更改,或近一半的更改。

    任何想要我的工具(如果您不是 Epsilon 用户,这些工具对您没有用)的 EEL 源代码副本,或者我的 awk 脚本副本的人,都可以免费获得。只是不要转售它们。请 给我发邮件


    摘要

    这是持续的构建步骤增量器系列中的另一个工具。我认为我喜欢它。时间会证明一切。我将在本网站上发布更改,并在 microsoft.public.vc.mfc 新闻组中发布更改通知。


    这些文章中表达的观点是作者的观点,不代表,也不被微软认可。

    发送邮件至newcomer@flounder.com提出关于本文的问题或评论。
    版权所有 © 2000,The Joseph M. Newcomer Co.保留所有权利
    www.flounder.com/mvp_tips.htm
  • © . All rights reserved.