链接到不同版本的.dll的 .lib 可能有哪些副作用

What are possible side-effects of linking against a .lib that is a different version of the .dll?

本文关键字:可能有 副作用 lib dll 版本 链接      更新时间:2023-10-16

我正在链接到较新的.lib,但在我的应用程序中使用较旧的.dll。这样做可能有什么副作用? 如果两个版本之间的函数原型相同,难道不应该一切正常吗? 如果较新版本更改了参数的默认值怎么办? 该值是在 .lib 中还是在.dll中?

C++默认值

是在调用站点编译的 - 因此 DLL 或 .lib 文件与此无关 - 更改标头将具有效果,而无需更改 ABI。

如果导出函数中的 ABI 没有更改,只要程序不使用新 .lib 中但不在新 DLL 中的新导出,您应该能够使用较旧的 DLL 和链接到较新的 .lib 的程序。

影响 ABI 的事情(我并不是说这是一个全面的列表):

- calling convention
- export name
- parameter list (including types)

"libtool 版本控制系统"(http://www.gnu.org/s/libtool/manual/libtool.html#Versioning)是一种用于识别共享库兼容性的技术。

请注意,如果您不使用 C 调用约定(即,导出名称将被"C++破坏"),那么从技术上讲,您几乎无法控制要导出的名称。


下面解释了某些Windows库(cygwin,pngdll)如何使用遵循libtool库版本控制技术的命名约定来管理向后兼容性。 这是来自 http://home.att.net/~perlspinr/libversioning.html 的网络档案 - 我在这里镜像它:

几个定义:

入口点位于外部 可访问的函数或变量 由 DLL 导出。界面是 所有这些导出的集合 给定中的函数和变量 库的版本。关于 libPNG 版本宏在 makefile.cygwin:

你只需要在以下情况下碰撞PNGDLL。 新 DLL 删除一个入口点 提供的旧 DLL。如果您添加新的 入口点,则新的 DLL 是一个 替换旧的, 因为新的提供了一切 旧的做到了。

当然,针对 新版本,它使用额外的 入口点,不适用于旧的 dll - 但没有人承诺过 向前兼容,仅向后兼容 兼容性。这就是西格温的方式 DLL 版本控制工作:

1) 遵循库工具版本控制 方案从 http://www.gnu.org/software/libtool/manual.html#Versioning:

So, libtool library versions are described by three integers:
current
    The most recent interface number that this library implements.
revision
    The implementation number of the current interface.
age
    The difference between the newest and oldest interfaces that this

库实现。换句话说, 库实现所有 接口编号范围为 当前数字 - 年龄到当前。

Updating libtool versioning:
   1.     Start with version information of 0:0:0 for each libtool

图书馆。

   2. Update the version information only immediately before a

公共 发布您的软件。不需要更频繁的更新, 和 只保证当前接口号变大 更快。

   3. If the library source code has changed at all since the last
      update, then increment revision (c:r:a becomes c:r+1:a).
   4. If any interfaces have been added, removed, or changed since the
      last update, increment current, and set revision to 0.
   5. If any interfaces have been added since the last public release,
      then increment age.
   6. If any interfaces have been removed since the last public
      release, then set age to 0. 

Never try to set the interface numbers so that they correspond to the
release number of your package. This is an abuse that only fosters
misunderstanding of the purpose of library versions. Instead, use the
-release flag (see Release numbers), but be warned that every

的发布 您的软件包将与任何其他版本不兼容。

2) On windows/cygwin, the DLLVER is 'c - a' (trust me, this is correct,

但更容易解释 示例)。

所以,这里有一个例子:libtool 版本为 5:4:3,表示 《公约》执行情况第4修订版 接口 5,恰好是 向后兼容三者 以前的接口定义。(即。 对于链接的应用程序是安全的 针对接口 5、4、3 和 2 至 在运行时加载 5:4:3 DLL)。

那么,让我们看看可能的历史 的神秘dll。我正在关注 c:r:A 上述更新规则。

oldest: interface definition 0, initial release:
0:0:0 (DLLVER = 0)    
removed an entry point:
1:0:0 (DLLVER = 1)    NOT backwards compatible!
but DLLVER does the right thing.
source code changed, but no added or removed entry points:
1:1:0 (DLLVER = 1)    
more source code changes:
1:2:0 (DLLVER = 1)    
In all of the previous three releases, 'c' - 'a' = DLLVER = 1.
removed an entry point (or renamed it):
2:0:0 (DLLVER = 2)    This is INCOMPATIBLE.
(But look: 'c' - 'a' = 2, so the DLLVER does the right thing)
added a new function:
3:0:1 (DLLVER = 2)    (this is BACKWARDS but not FORWARDS compatible.
However, the DLLVER 'c' - 'a' still is 2, so that is good.)
add eight more exported functions all at once
4:0:2 (DLLVER = 2)    
add another function:
5:0:3 (DLLVER = 2)
source code changes, but no new interfaces:
5:1:3 (DLLVER = 2)    
again:
5:2:3 (DLLVER = 2)    
again:
5:3:3 (DLLVER = 2)    
again:
5:4:3 (DLLVER = 2)    

所有这些 DLL 与 DLLVER = 2 (2:0:0, 3:0:1, 4:0:2, 5:0:3, 5:1:3, 5:2:3、5:3:3 和 5:4:3) 都是 严格向后兼容:它是 保证任何较新的 DLL 在 系列可以由 exe 加载 是针对较旧的 DLL 编译的 该系列。

在 1.2.3 中,DLLVER 是 12。让我们 假装是 12 的"c"-"a", 并且"c"= 12,"a"= 0。

在 [libpng] 1.2.4 中,您只需添加 一些新功能 - 但没有 删除任何。所以,新的库工具编号 是 13:0:1 -- DLLVER 仍然是 12。

不要

这样做。

我以前处理过"新 LIB,旧 DLL"问题,诊断起来真的非常烦人。只有当每个公开可见的类型都具有完全相同的签名时,它才是"安全的",这基本上意味着库作者必须优先考虑二进制兼容性。否则,您最终会遇到奇怪的堆损坏错误,这些错误通常直到程序运行一段时间后才会显现出来。

要回答您的具体问题:默认参数实际上是头文件的属性,而不是库的属性。

默认参数应该在 .h 文件中,所以这部分可能没问题。

否则,当.DLL没有按预期执行时,可能的结果通常是很难找到错误。

且仅当旧版本的 dll 之间保持二进制兼容性时,这才没问题。

简单来说。如果:

  • 工具使用的 DLL 头文件没有更改,并且
  • 没有添加或删除导出的符号,您可能没问题。

如果不满足这些条件中的任何一个,您很有可能会遇到一些非常有趣的错误/崩溃/内存涂鸦等。