【问题标题】:ODR violation when linking static and dynamic library链接静态库和动态库时违反 ODR
【发布时间】:2019-09-02 01:45:40
【问题描述】:

将包含不同版本的 boost 的静态 cpp 库和动态 cpp 库链接是否会违反 ODR?

我正在开发一个 iphone 应用程序。对于最终的可执行文件,我需要链接一个静态库,比如 libstatic1.a 和一个动态框架,比如 libdyanamic1。

libstatic1.a 包含某些版本的 boost,比如 boost 1.x,而 libdynamic1 包含另一个版本的 boost,比如 boost 1.y。现在链接这两者的最终可执行文件会违反 ODR 规则吗?

libdynamic1 中的符号可见性: 我使用 nm -g -C libdynamic1 检查了 libdynamic1 中存在的符号,并观察到列表中存在 boost 线程池和 boost 文件系统的符号。

如果我违反了 ODR,我有哪些选择来处理这种情况? (到目前为止,我已经在多台设备上测试了可执行文件,没有遇到任何问题。)

【问题讨论】:

  • 通常会有一个标志让链接器忽略这种情况
  • 你碰巧知道国旗吗?它将如何运作?它会解决对其中一个库的所有 boost 调用吗?
  • 这一切都取决于一个问题:libdynamic1 是导出一些增强的东西还是只是在内部使用它而不导出任何符号?
  • nm -g 核对。它确实导出了一些与线程、日期时间和异常相关的 boost 内容。
  • 好吧,那么你很可能会遇到一些问题……

标签: c++ iphone clang one-definition-rule


【解决方案1】:

该标准只讨论“程序”,其中“程序”是一组“链接在一起”的翻译单元,每个翻译单元由一系列声明[basic.link] 组成。当涉及到涉及动态库的问题时,争论 ODR,它也只涉及“程序”,并不是那么直接。由于“程序”需要包含main 函数[basic.start.main]/1,因此动态链接库通常不能单独作为“程序”。

严格来说,我认为动态库必须被视为另一组翻译单元,它们与其他翻译单元“链接”以形成最终程序。因此,只有在所有图像都加载到内存中并且动态链接完成后,程序才会真正完成(运行时动态链接似乎会使问题进一步复杂化,但我猜这里可以忽略)。从这个意义上说,您的问题中描述的程序(链接静态库和动态库,其中每个库都使用不同版本的 boost)几乎肯定会违反 ODR,因为您将拥有多个翻译单元,例如,使用the same实体[basic.def.odr]/12的不同定义。

然而,在实践中,这个问题高度依赖于平台和工具链。在 ABI 级别,您通常会发现符号可以具有的链接类型比您在 C++ 中的语言级别发现的更不同。例如,在 Windows 上,您通常必须在构建动态库时明确指定应导出哪些符号,默认情况下,所有名称都是库的内部名称。另一方面,在基于 ELF 的 Linux 上,情况并非如此。但是,您似乎可以使用 -fvisibility=hidden 选项将 GCC 切换到更类似于 Windows 的默认值,您的库只会导出您明确告诉它的内容。请注意,您不得与库导出的接口中的 boost 有任何关系,因为这显然会导致在您的情况下出现未定义的行为……

【讨论】:

  • 谢谢迈克尔!我意识到这些问题的平台依赖性。我正在为 iOS 做这个。
  • 限制可见性本质上与将所有受限符号重命名为内部名称相同。请注意,GNU 发明了一种方法来定义从不重命名的符号。这是一个非常有问题的概念。
猜你喜欢
  • 2010-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-23
  • 2011-03-16
  • 1970-01-01
  • 2019-08-13
  • 1970-01-01
相关资源
最近更新 更多