从 VC8 (VS2005) 到 VC9 (VS2008) 的移植问题是什么?

发布于 2024-07-08 21:32:17 字数 1911 浏览 7 评论 0原文

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

我使用的移植过程是:

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

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

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

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

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

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

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

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

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

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

现在真正的难题是:我遇到了 VC8 和 VC9 项目之间启动顺序的差异。 该程序使用一个小对象分配器,该分配器以 Andrei Alexandrescu 的《现代 C++ 设计》一书中的 Loki 为模型。 该分配器使用主程序模块中定义的全局变量进行初始化。

在 VC8 下,该全局变量是在程序启动之初由模块 crtexe.c 中的代码构造的。 在VC9下,第一个执行的模块是crtdll.c,这表明启动顺序被改变了。 正在启动的 DLL 似乎会在全局对象初始化统计信息之前分配和释放内存,从而混淆小对象分配器,从而导致一些虚假诊断。 该程序的运行似乎没有受到重大影响,但质量检查人员不会允许虚假诊断通过他们。

是否有某种方法可以在加载 DLL 之前强制构建全局对象?

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

I have inherited a very large and complex project (actually, a 'solution' consisting of 119 'projects', most of which are DLLs) that was built and tested under VC8 (VS2005), and I have the task of porting it to VC9 (VS2008).

The porting process I used was:

  1. Copy the VC8 .sln file and rename it
    to a VC9 .sln file.
  2. Copy all of
    the VC8 project files, and rename
    them to VC9 project files.
  3. Edit
    all of the VC9 project files,
    s/vc8/vc9.
  4. Edit the VC9 .sln,
    s/vc8/vc9/
  5. Load the VC9 .sln with
    VS2008, and let the IDE 'convert'
    all of the project files.
  6. Fix
    compiler and linker errors until I
    got a good build.

So far, I have run into the following issues in that last step.

1) A change in the way decorated names are calculated, causing truncation of the names.

This is more than just a warning (http://msdn.microsoft.com/en-us/library/074af4b6.aspx). Libraries built with this warning will not link with other modules. Applying the solution given in MSDN was non-trivial, but doable. I addressed this problem separately in How do I increase the allowed decorated name length in VC9 (MSVC 2008)?

2) A change that does not allow the assignment of zero to an iterator. This is per the spec, and it was fairly easy to find and fix these previously-allowed coding errors. Instead of assignment of zero to an iterator, use the value end().

3) for-loop scope is now per the ANSI standard. Another easy-to-fix problem.

4) More space required for pre-compiled headers. In some cases a LOT more space was required. I ended up using /Zm999 to provide the maximum PCH space. If PCH memory usage gets bumped up again, I assume that I will have to forgo PCH altogether, and just endure the increase in what is already a very long build time.

5) A change in requirements for copy ctors and default dtors. It appears that in template classes, under certain conditions that I haven't quite figured out yet, the compiler no longer generates a default ctor or a default dtor. I suspect this is a bug in VC9, but there may be something else that I'm doing wrong. If so, I'd sure like to know what it is.

6) The GUIDs in the sln and vcproj files were not changed. This does not appear to impact the build in any way that I can detect, but it is worrisome nevertheless.

Note that despite all of these issues, the project built, ran, and passed extensive QA testing under VC8. I have also back-ported all of the changes to the VC8 projects, where they still build and run just as happily as they did before (using VS2005/VC8). So, all of my changes required for a VC9 build at least appear to be backward-compatible, although the regression testing is still underway.

Now for the really hard problem: I have run into a difference in the startup sequence between VC8 and VC9 projects. The program uses a small-object allocator modeled after Loki, in Andrei Alexandrescu's Book Modern C++ Design. This allocator is initialized using a global variable defined in the main program module.

Under VC8, this global variable is constructed at the very beginning of the program startup, from code in a module crtexe.c. Under VC9, the first module that executes is crtdll.c, which indicates that the startup sequence has been changed. The DLLs that are starting up appear to be confusing the small-object allocator by allocating and deallocating memory before the global object can initialize the statistics, which leads to some spurious diagnostics. The operation of the program does not appear to be materially affected, but the QA folks will not allow the spurious diagnostics to get past them.

Is there some way to force the construction of a global object prior to loading DLLs?

What other porting issues am I likely to encounter?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

慵挽 2024-07-15 21:32:17

是否有某种方法可以在加载 DLL 之前强制构建全局对象?

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

Is there some way to force the construction of a global object prior to loading DLLs?

How about the DELAYLOAD option? So that DLLs aren't loaded until their first call?

沧桑㈠ 2024-07-15 21:32:17

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

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

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

That is a tough problem, mostly because you've inherited a design that's inherently dangerous because you're not supposed to rely on the initialization order of global variables.

It sounds like something you could try to work around by replacing the global variable with a singleton that other functions retrieve by calling a global function or method that returns a pointer to the singleton object. If the object exists at the time of the call, the function returns a pointer to it. Otherwise, it allocates a new one and returns a pointer to the newly allocated object.

The problem, of course, is that I can't think of a singleton implementation that would avoid the problem you're describing. Maybe this discussion would be useful: http://www.oneunified.net/blog/Personal/SoftwareDevelopment/CPP/Singleton.article

滿滿的愛 2024-07-15 21:32:17

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

因为变量和分配器的行为依赖于某些(当时未知的)任意启动顺序,我可能会修复这个问题,这样将来就不再是问题了。 我想你实际上是在问是否有人知道如何在 VC9 中做一些巫术来使问题消失。 我也有兴趣听听。

That's certainly an interesting problem. I don't have a solution other than perhaps to change the design so that there is no dependence on undefined behavior of the order or link/dll startup. Have you considered linking with the older linker? (or whatever the VS.NET term is)

Because the behavior of your variable and allocator relied on some (unknown at the time) arbitrary order of startup I would probably fix that so that it is not an issue in the future. I guess you are really asking if anyone knows how to do some voodoo in VC9 to make the problem disappear. I am interested in hearing it as well.

心意如水 2024-07-15 21:32:17

怎么样,

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

How about this,

  1. Make your main program a DLL too, call it main.dll, linked to all the other ones, and export the main function as say, mainEntry(). Remove the global variable.
  2. Create a new main exe which has the global variable and its initialization, but doesn't link statically to any of the other application DLLs (except for the allocator stuff).
  3. This new main.exe then dynamically loads the main.dll using LoadLibrary(), then uses GetProcAddress to call mainEntry().
染墨丶若流云 2024-07-15 21:32:17

问题的解决方案比我最初想象的更简单。 初始化顺序问题是由于存在多个从 std 容器类型派生的类型的全局变量而引起的(这是我在该公司任职之前的一个基本设计缺陷)。 解决方案是用单例替换所有此类全局变量。 大约有 100 人。

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

The solution to the problem turned out to be more straightforward than I originally thought. The initialization order problem was caused by the existence of several global variables of types derived from std container types (a basic design flaw that predated my position with that company). The solution was to replace all such globals with singletons. There were about 100 of them.

Once this was done, the initialization (and destruction) order was under programmer control.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文