3

我继承了一个在 VC8(VS2005)下构建和测试的非常庞大而复杂的项目(实际上是一个由 119 个“项目”组成的“解决方案”,其中大部分是 DLL),我的任务是将它移植到 VC9 (VS2008)。

我使用的移植过程是:

  1. 复制 VC8 .sln 文件并将其重命名为 VC9 .sln 文件。
  2. 复制所有 VC8 项目文件,并将它们重命名为 VC9 项目文件。
  3. 编辑所有 VC9 项目文件,s/vc8/vc9。
  4. 编辑 VC9 .sln, s/vc8/vc9/
  5. 使用 VS2008 加载 VC9 .sln,并让 IDE“转换”所有项目文件。
  6. 修复编译器和链接器错误,直到我得到一个好的构建。

到目前为止,我在最后一步中遇到了以下问题。

1) 修饰名称的计算方式发生变化,导致名称被截断。

这不仅仅是一个警告 ( http://msdn.microsoft.com/en-us/library/074af4b6.aspx )。使用此警告构建的库不会与其他模块链接。应用 MSDN 中给出的解决方案并非易事,而是可行的。我在如何增加 VC9 (MSVC 2008) 中允许的修饰名称长度?

2) 不允许将零分配给迭代器的更改。这是符合规范的,很容易找到并修复这些以前允许的编码错误。不要将零分配给迭代器,而是使用值 end()。

3) for-loop 范围现在符合 ANSI 标准。另一个容易解决的问题。

4) 预编译头文件需要更多空间。在某些情况下,需要更多的空间。我最终使用 /Zm999 来提供最大的 PCH 空间。如果 PCH 内存使用量再次增加,我认为我将不得不完全放弃 PCH,并忍受已经很长的构建时间的增加。

5) 对复制 ctor 和默认 dtor 的要求有所改变。似乎在模板类中,在我还没有完全弄清楚的某些条件下,编译器不再生成默认 ctor 或默认 dtor。我怀疑这是 VC9 中的一个错误,但可能还有其他我做错的事情。如果是这样,我肯定想知道它是什么。

6) sln 和 vcproj 文件中的 GUID 没有改变。这似乎不会以我可以检测到的任何方式影响构建,但仍然令人担忧。

请注意,尽管存在所有这些问题,该项目还是在 VC8 下构建、运行并通过了广泛的 QA 测试。我还将所有更改移植到 VC8 项目中,它们仍然像以前一样愉快地构建和运行(使用 VS2005/VC8)。因此,我为 VC9 构建所需的所有更改至少看起来是向后兼容的,尽管回归测试仍在进行中。

现在解决真正困难的问题:我遇到了 VC8 和 VC9 项目的启动顺序不同。该程序使用了一个仿照 Loki 的小对象分配器,在 Andrei Alexandrescu 的 Book Modern C++ Design中。该分配器使用主程序模块中定义的全局变量进行初始化。

在 VC8 下,这个全局变量是在程序启动的最开始时从模块 crtexe.c 中的代码构造的。在VC9下,第一个执行的模块是crtdll.c,表示启动顺序发生了变化。正在启动的 DLL 似乎通过在全局对象初始化统计信息之前分配和取消分配内存来混淆小对象分配器,这会导致一些虚假的诊断。该程序的运行似乎没有受到实质性影响,但 QA 人员不会允许虚假诊断通过他们。

有没有办法在加载 DLL 之前强制构建全局对象?

我可能会遇到哪些其他移植问题?

4

5 回答 5

1

这是一个棘手的问题,主要是因为您继承了一个本质上很危险的设计,因为您不应该依赖全局变量的初始化顺序。

这听起来像是您可以尝试通过将全局变量替换为单例来解决的问题,其他函数通过调用返回指向单例对象的指针的全局函数或方法来检索该变量。如果对象在调用时存在,则函数返回一个指向它的指针。否则,它分配一个新对象并返回一个指向新分配对象的指针。

当然,问题是我想不出一个可以避免您描述的问题的单例实现。也许这个讨论会很有用:http ://www.oneunified.net/blog/Personal/SoftwareDevelopment/CPP/Singleton.article

于 2009-02-04T20:37:16.573 回答
1

有没有办法在加载 DLL 之前强制构建全局对象?

DELAYLOAD 选项怎么样?所以 DLL 在第一次调用之前不会被加载?

于 2009-02-03T20:22:01.890 回答
0

这个怎么样,

  1. 让你的主程序也成为一个 DLL,将其命名为 main.dll,链接到所有其他程序,然后将主函数导出为 mainEntry()。删除全局变量。
  2. 创建一个新的主 exe,它具有全局变量及其初始化,但不静态链接到任何其他应用程序 DLL(分配器的东西除外)。
  3. 这个新的 main.exe 然后使用 LoadLibrary() 动态加载 main.dll,然后使用 GetProcAddress 调用 mainEntry()。
于 2009-02-03T23:37:14.167 回答
0

这当然是一个有趣的问题。除了改变设计以便不依赖于未定义的订单行为或链接/dll 启动之外,我没有其他解决方案。您是否考虑过使用旧链接器进行链接?(或任何 VS.NET 术语)

因为您的变量和分配器的行为依赖于一些(当时未知)任意启动顺序,所以我可能会修复它,以便将来不会出现问题。我想你真的在问是否有人知道如何在 VC9 中做一些巫术来使问题消失。我也有兴趣听听。

于 2008-10-31T20:30:38.167 回答
0

事实证明,这个问题的解决方案比我最初想象的要简单。初始化顺序问题是由从标准容器类型派生的几个全局变量类型的存在引起的(一个基本的设计缺陷,早于我在该公司的职位)。解决方案是用单例替换所有这些全局变量。其中大约有100个。

一旦完成,初始化(和销毁)顺序就在程序员的控制之下。

于 2012-03-28T20:07:06.973 回答