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

无需重新编译的 MSVC IDE 版本控制方案

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.27/5 (5投票s)

2009年1月19日

CPOL

10分钟阅读

viewsIcon

20796

一种避免在使用 RCSTamp 更新 .RC 文件时进行不必要的重新编译的方法。

yav_versioning_01_Jan__16_13_13.jpg

引言

本文介绍了一种方法——也是我迄今为止发现的唯一一种方法——在 Microsoft Visual C++ IDE 中使用另一篇 CodeProject 文章中提出的版本控制方案时,避免不必要的重新编译。

虽然此特定解决方案专为 Microsoft Visual Studio 设计——顺便说一句,它也适用于 Express 版本——但类似的安排应该可以在大多数提供在构建前执行用户命令钩子的 IDE 上运行。

我主要将其用于 MSVC 2008 C++ Express,但 2005 版本也提供了指定构建前操作的设施,尽管我没有亲自检查早期版本是否在此问题上。

此外,由于我既不使用前面提到的 CodeProject 文章中提出的 VerCopy 例程,也不使用 VerHeader 工具及其生成或更新的头文件,因此我的代码中不显示它。如果你想使用 VerCopy,请将其命令保留在你的后置构建步骤中。它不会影响文件日期和时间,因此不会引起任何问题。

如前所述,我没有使用 Verheader 工具,因为对我来说,它带来的问题比解决的更多——至少在 Windows 下是这样。稍后将详细介绍。

我的方案确实使用了 RCStamp 工具,该工具也在前面的 CodeProject 文章中使用并引用,有关它的任何信息,请参阅原始 文章

背景

在不久前找到上述 CodeProject 文章后,我很快意识到,虽然它实现了我想要的功能,但它导致了过于频繁的重新编译,即使没有对源文件进行任何更改。

对我来说,重新编译的发生频率太高了,而且更令人恼火的是,它们发生在意想不到的时候,尤其是在我因任何原因分心然后回到我的项目——渴望继续调试一些新代码时。

每次我们开始调试时,MSVC 都会检查以确保代码是最新的,这通常是一件好事。当然,在前面提到的情况下,它永远不会是,因为至少有一个文件,即 .rc 资源文件,是在上一次编译的最后一步被修改的,因此它会强制进行新的编译,让你——再次——等待。而且,如果你还使用头文件,问题只会成倍增加,因为有更多的文件“过时”了。

这在某些我有时需要(或曾经需要)出于某种原因使用的较慢的机器上尤其令人沮丧。

除了以上所有原因之外,不必要的重新编译在某种程度上削弱了拥有构建编号——一种代码更改的唯一标识符——的很大一部分目的,因为它在没有任何更改的情况下不必要地增加了数字。

在尝试了各种方法来解决这个问题——但都没有真正成功——我最终决定尝试彻底解决这个问题——或者理解为什么我必须忍受这个问题。

我首先意识到的是,使用早期文章中提出的基本设置,无法避免这个问题。一次成功的编译会调用后置构建步骤,该步骤又会修改 .rc 文件。下次,当 IDE 被要求检查是否有任何更改时,它会检测到 .rc 文件中的此更改,并重新编译,或者至少重新链接应用程序,从而再次更新 .rc 文件……我们又回到循环中了。

创建头文件,该文件需要包含在某个地方,从而使包含它的文件过时,这只会使问题更加严重。此外,当然,从头文件中包含的构建编号与项目中的 .rc 文件中的构建编号总是相差一。在许多情况下,这差别不大,因为头文件中的构建编号与链接的资源中的构建编号一致。但是,如果你要检查项目资源文件的源代码,就需要牢记这一点。

在我早期避免“问题”的尝试中,我使用 touch 命令来更新各种文件的文件时间,有时我成功地避免了重新编译,但随后从头文件信息中获得的版本信息与 .rc 文件中的版本信息不一致。

即使将文件名命名为奇特的扩展名 .info 也不能欺骗 IDE。它似乎仍然检测到依赖关系,并执行“适当的操作”。虽然 MS 提供了通过更改 SYSINCL.DAT 文件来排除文件的方法——至少对于某些版本——但使用此功能也无法解决实际问题。

当然,要避免一些问题的一种方法是完全避免额外的头文件,而是使用一些可用函数——例如 GetFileVersionInfo() ——来提取然后解析相关数据。

这仍然会留下不必要的重新编译的问题,并且在应用程序中而不是在外部应用程序中解析数据,当然也会为每个应用程序添加必要的解析代码,尽管这通常不会造成太大问题。在大多数情况下,额外的代码与其余部分以及避免重新编译所需的精力相比,可以忽略不计。

修复方法

首先,放弃额外的头文件,将你的问题减少一半以上。

然后,由于真正的问题是 .rc 文件不可避免地重新编译,为什么不在我们更改它之后立即处理它呢?我们知道我们正在更改哪个文件,并且资源编译器有一个相对简单的命令行,所以我们只需在调用 RCStamp 后,立即调用资源编译器。

如果我们这样做是在构建前步骤中——只有当存在其他导致重新编译的更改时,此步骤才会被调用——那么链接步骤将留下依赖关系,使得没有任何未完成的更改会要求重新编译。

不幸的是,我们不能依赖 IDE 来检测构建前步骤中对 .rc 文件所做的更改,因为当此步骤被调用时,所有依赖项扫描都已完成,而且据我所知,没有办法重新启动它。

在某些方面,无论我们将所有这些工作放在构建前步骤还是后置构建步骤中,差别不大,只是在构建前步骤中进行可以使资源文件中的构建编号与链接到可执行文件中的构建编号保持一致。

在后置构建步骤中进行工作会使磁盘上的 .rc 文件中的构建编号始终比链接到的资源中的值高一。

当然,要使用版本信息,现在需要调用函数 GetFileVersionInfo() 并提取版本号。

那么,我们该怎么做呢?

在构建前步骤中,添加以下内容

描述

Updating Version  ....

命令行

RCStamp  -v  $(ProjectName)r.rc *.*.+.*
rc.exe /foDebug/$(ProjectName)r.res .\$(ProjectName)r.rc

要访问正确的对话框,请按 Alt-F7 打开“项目属性”对话框,然后在左侧窗格中,展开“构建事件”项,单击“命令行”项的右侧字段,然后将适当的数据粘贴到字段中。

要编辑数据,请单击字段右侧会出现的“...”按钮。

如果你的 .rc 文件包含其他文件——它们通常会——那么,你必须在资源编译器行中添加适当的 "/I include/path" 项。请记住,此行的内容完全由你负责。虽然你可以使用 IDE 定义的宏,但它将使用你编写的行。它不会搜索你自己在命令行中指定的任何其他路径。

那么,如果你想要或需要头文件呢?

如果你确实想在 Windows 下继续使用头文件,那么,至少,你将不得不做(相当多)更多的工作。

将信息提取到头文件中很容易——使用 VerHeader。真正的问题将是如何同时编译包含此头的(所有)源文件。因此,我建议你尽量减少包含头文件的文件数量——以及大小。也许,一个只定义一组全局变量的头文件,不要包含太多其他内容,也没有其他代码,以使命令行尽可能直接,然后尽可能快速无痛地编译。

对我自己而言,只要我只在 Windows 环境中工作,额外的努力就不值得花费时间来实现和测试它。

关注点

如果你在构建同一个应用程序的不同版本时使用这种类型的构建编号方案,例如 Windows 下的 ANSI 和 Unicode,那么,只要你使用的是通用的代码库,你就必须选择是坚持每个配置一个“构建编号”——以及相关的 .rc 文件——还是一个代表代码库的单一构建编号。

这个问题双方都有争论和权衡,你必须相应地调整你的程序,并且只为你选择的基础配置更新构建编号。

如果你选择使用单一构建编号和单一 .rc 文件——并且希望所有不同版本都有相同的构建编号——那么,你将需要**仅**在一个配置中添加更新代码,然后**在更新第一个配置之后**重建**所有其他配置**,但至少,不会有不必要的重新编译,并且构建编号的任何更改确实代表了源代码的某些更改。

跨平台构建编号怎么样?

如果你需要跨平台,那么,由于 *nix 系统不使用相同的 .rc 文件——但 Windows 使用,这意味着你必须使用 .rc 文件——你可能不得不使用头文件,但要将其隐藏在 MSVC IDE 之外。这样,MSVC IDE 就不会因为头文件更改而重新编译,而对于非 Windows 平台,你将拥有相应的头文件。

在此之后,设置好,使得构建编号仅在所需点递增,并且所有版本都在该点**之后**构建。

在这种情况下,你当然也不需要 Linux 版本中用于从 Windows 下的 .rc 文件提取和解析版本号的代码。

我们应该何时增加构建编号?

一个我认为肯定会引起很大争议的问题是,何时增加构建编号。我的方案目前是在我的“主要发行版”版本——碰巧是 Unicode 版本——编译时增加的。这样,所有大量的调试编译都不会不必要地增加构建编号。但是,这种方式确实有一些我仍在了解的影响。

现在,我很高兴不再需要等待那些额外的编译,并且拥有比以前更有意义的构建编号。

目前的情况是,即使没有进行任何代码更改,构建编号也会(不必要地)增加,如果:

  • 构建环境发生变化——即项目配置发生某些变化
  • 出于任何原因,“主”版本的构建未能成功完成——用户中止、编译器或链接器问题……

历史

目前还没有什么令人兴奋的。

© . All rights reserved.