VC ++替换了不同对象的定义,GCC等

时间:2010-01-13 11:44:18

标签: c++ c windows visual-c++ c-preprocessor

我有一个使用许多静态库的大型应用程序,它是独立于平台并在Windows和Linux下部署的。

所有静态库和main()本身都使用两个定义进行编译:

-DVERSION=1.0.0 -DBUILD_DATE=00.00.0000

这些定义由每个静态lib内部的宏使用,并在main内部用于将当前lib版本存储在类似注册表的类中。

在GCC / Linux下,这非常有效 - 您可以列出所有链接的模块并显示其真实版本和builddate,例如:

  • ImageReader 0.5.4(12.01.2010)
  • 压缩1.0.1(03.01.2010)
  • SQLReader 0.3.3(22.12.2009)

但是:当我用VisualStudio 2005 SP1链接完全相同的代码时,我只得到最后编译模块的版本和构建日期:

  • ImageReader 0.5.4(12.01.2010)
  • 压缩0.5.4(12.01.2010)
  • SQLReader 0.5.4(12.01.2010)

有人有想法吗?这是VC ++链接器的“优化”问题吗?

6 个答案:

答案 0 :(得分:2)

嗯,Visual Studio支持包含多个项目的解决方案。它的依赖引擎能够检测到更改的宏值需要重新编译项目。 Occam的剃刀说,libs只是重建并获得了新的VERSION宏值。

答案 1 :(得分:0)

预处理器定义由编译器的预处理器阶段解析,而不是链接器。

虽然在VC ++中可能存在预编译头文件的问题。

否则,要真正告诉我希望看到源代码正在进行版本的实际打印(日期)。

答案 2 :(得分:0)

这与Visual Studio链接器没有任何关系;它只是预处理器宏的问题,所以问题已经在编译器开始工作之前就已经开始了。

Visual Studio构建中的编译行是什么样的?我的第一个想法是,由于某种原因,定义(-D参数)都被添加到一个命令行,最后一个总是获胜。

答案 3 :(得分:0)

我假设您有一个应用程序,然后链接到这些库,并且在这个应用程序中,您看到相同的版本号。

确保该应用程序也没有这些-D开关。如果没有,那么我的猜测是VC编译器很聪明并使用相同的-D开关触发依赖项目的构建,而不是通过项目文件触发构建。

此外,版本化这些二进制文件的最佳方法是直接在headers / source中使用宏,并为每个库提供所有唯一的名称。这样他们就不会相互干扰(除非你将其中一个标题克隆到一个应用程序中,复制宏defs),并且你不再依赖编译器来正确地进行操作。

答案 4 :(得分:0)

如果您使用的是预编译的标头,则可能会出现问题。尝试通过禁用预编译的头文件选项来构建应用程序。

答案 5 :(得分:0)

“这些定义由每个静态lib内部的宏使用,并在main内部用于将当前lib版本存储在类似注册表的类中。”

你有没有违反一个定义规则?如果您有一个类,则它应该在所有库中都有一个定义。听起来类定义依赖于版本宏,该宏在程序的不同部分定义不同,因此您违反了ODR。对此的惩罚是未定义的行为。

似乎MS链接器通过忽略除第一个定义之外的所有内容来利用ODR。毕竟,如果X的所有定义都相同,那么你可以忽略除第一个之外的所有定义。