【问题标题】:Crosscompiler Binary compatibility in CC 中的交叉编译器二进制兼容性
【发布时间】:2011-10-12 15:03:47
【问题描述】:

我需要验证一些我有疑问的事情。如果共享库 (.dll) 是用 C 语言编写的,符合 C99 标准并在编译器下编译。说MinGw。然后根据我的经验,它是二进制兼容的,因此可以从任何其他编译器中使用。说 MS Visual Studio。我说以我的经验,因为我已经成功地尝试过不止一次。但我需要验证这是否是一个规则。

此外,我想问一下是否确实如此,那么为什么完全用 C 编写的库(例如 openCV)不为每个不同的操作系统提供编译的二进制文件?我知道最明显的原因是设置所有编译时参数,但除此之外没有一个对吗?

编辑:我添加了一个附加问题,我认为这是对原始问题的逻辑扩展。这不就是创建一个封闭源代码库的方式吗?由于提供源的选项在那里消失了,因此提供二进制文件是唯一的选择。在这种情况下,为尽可能多的架构提供二进制文件是理想的结果,而 C 显然是在系统和编译器之间具有最佳可移植性的选择。对吧?

【问题讨论】:

  • 非常有趣的问题。奇怪的是,即使我在 80 年代初期和中期还是 UN*X 世界中的调试器专家,我也从未真正考虑过这一点。当然,我主要使用符号表作为指导,但仍然可能存在结构中的位打包和将参数推入堆栈的问题。我猜在那个世界中,大多数代码都是/曾经使用制造商的编译器或 GCC 的一个或另一个版本编译的,因此存在固有的一致性,但这并不完全符合您的要求。

标签: c shared-libraries binary-compatibility


【解决方案1】:

编译到特定架构的共享库或 dll 可以链接到由针对相同架构的其他编译器编译的应用程序。 (通过架构,我的意思是处理器/操作系统组合)。但是对于库开发人员来说,针对所有可能的架构进行编译是不切实际的。此外,当库以源代码形式分发时,用户可以构建针对其特定要求优化的二进制文件。

【讨论】:

    【解决方案2】:

    在 Windows 世界中的 C 编译器(MSVC 和 GCC/MinGW)的特定情况下,您对二进制兼容性的假设是正确的。可以将 GCC 编译的 C 接口 DLL 链接到 Visual Studio 中的程序。这就是 ffmpeg 等 C99 项目允许开发人员使用 Visual Studio 编写应用程序的方式。只需从 DLL 中使用 Microsoft 工具链中的 lib.exe 创建导入库。反之亦然,使用 mingw.org 的 pexports 或更好的 mingw-w64 的 gendef 工具,可以为 MSVC 生成的 DLL 创建 GCC 导入库。

    当您进入 C++ 接口世界时,这种方便的互操作性就会失效,因为 MSVC 和 GCC 的 ABI 不同且不兼容。它可能有效,也可能无效,没有做出任何保证,也没有(目前)正在努力改变它。此外,调试信息显然是不同的,直到有人在 GCC 中编写了一个与 MSVC 的调试器兼容的调试信息生成器/写入器(当然还有 gdb 支持)。

    我不认为 C99 对函数声明或在符号定义中处理参数的方式有任何特别的改变,所以这里也应该没有问题。

    请注意,正如 Vijay 所说,仍然存在架构差异,因此在链接到 AMD64 库时不能使用 x86 库。


    还回答您关于封闭源代码二进制文件和为所有可用编译器/架构分发版本的其他问题。

    这正是您创建封闭源代码二进制文件的方式。除了导入库之外,隐藏 DLL 的导出也很重要,使 DLL 本身无法用于链接(如果您不希望客户端代码使用库中的私有函数,请参见例如 @ 的输出987654321@ 在 MSOffice DLL 上,那里有很多隐藏的东西)。您可以使用 GCC 实现相同的目标(我相信,从未使用或尝试过),使用 __attribute(hidden) 等...

    一些编译器的具体点:

    1. MSVC 通过 /MT、/MD 和 /LD 附带四个(实际上,在较新版本中仅剩下三个)不同的运行时库。最重要的是,您必须为每个版本的 Visual Studio(包括 Service Pack)提供构建以确保兼容性。但这对你来说是闭源二进制和 Windows...

    2. GCC 没有这个问题; MinGW 始终链接到 Windows 提供的 msvcrt.dll(自 Windows 98 起),与 /MD 等效(也可能与 /MDd 等效的调试库)。但是我有两个版本的 MinGW(mingw.org 和 mingw-w64)不保证二进制兼容性。后者更完整,因为它提供 64 位选项和 32 位选项,并提供更完整的标头/库集(包括 DirectX 和 DDK 的大部分)。

    【讨论】:

    • 感谢您的回答,我猜当然不同的架构需要用其他编译器重新编译。 C++接口是什么意思?如果您将 C 代码封装在 extern "C" {... } 中,那么在所有编译器中,您可以从外部库调用 C 代码,这难道不一样吗?我的问题还涉及如何开发封闭源代码库。您只需要提供二进制文件,因此公认具有最佳二进制可移植性的 C 将是一个显而易见的选择,对吧?
    • Lefteris:查看我的更新,是的,extern "C" { ... } 是您提供 C 接口所需要的。可以通过使用 g++ 编译来创建 C++ 接口,并省略该部分,这可以让名称修改发挥作用,这是交叉编译器兼容性的阻碍之一。
    • 非常感谢您的回答,非常详细。至于我知道的名称修改,不幸的是,我过去曾多次遇到过这种情况,这就是促使我在一些项目中转向 C 以实现可移植性的原因。
    【解决方案3】:

    一般规则是,如果您的操作系统/CPU 组合具有标准 ABI,并且如果该 ABI 对您的语言足够强大,则大多数编译器将遵循该 ABI,因此将是二进制兼容的,允许您链接库(共享或静态)用不同的编译器编译到用其他编译器编译的程序就好了。

    问题在于,大多数 ABI 都相当薄弱——它们是围绕 C 和 FORTRAN 等低级语言设计的,并且可以追溯到 C++ 等面向对象语言之前的日子。因此,它们往往缺乏对函数重载、用户定义的运算符、异常、全局构造函数和析构函数、虚函数、继承等 C++ 所需的支持。

    在设计 C++ 时就认识到了这一缺陷,这就是 C++ 具有 extern "C" 的原因——这会导致编译器将自身限制为某些功能的标准 ABI,同时禁用 ABI 通常不具备的所有额外 C++ 功能支持。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-03-07
      • 2011-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-18
      • 1970-01-01
      相关资源
      最近更新 更多