混合来自不同编译器的 C++ 代码
Posted
技术标签:
【中文标题】混合来自不同编译器的 C++ 代码【英文标题】:Mixing C++ code from different compilers 【发布时间】:2012-08-20 15:06:56 【问题描述】:假设我有两个项目想要链接在一起:
使用 Visual C++ 编译为 DLL 文件的 C++ 库。 使用库中的类使用 C++ Builder 编译的 C++ 可执行文件。我意识到没有标准的 C++ ABI,任何将这两个 C++ 项目直接链接在一起的尝试都会失败。有什么好的自动化方法可以创建兼容层来让我完成此任务?
例如,可以想象 C++ 库可以通过 C 接口公开自己。然后可执行文件将包含一些 C++ 类,这些类包装了 C++ 库公开的 C 接口。由于有一个标准的 C ABI,它可以工作。
唯一的问题是如何自动创建 C 接口和 C++ 包装类 - 手动维护这不是一种选择。 SWIG 项目看起来很有希望,但不幸的是,C++ 并不是 SWIG 在其网站上列出的出口之一。有没有办法用 SWIG 做我想做的事?或者除了 SWIG 之外还有其他项目可以帮助我完成这项任务吗?
或者我是不是走错了路?
编辑:核心 C++ 库旨在跨平台。显然,可执行文件是特定于 Windows 的。我不想将核心库污染到无法在其他平台上编译的程度。
【问题讨论】:
+1 努力让您的核心业务逻辑跨平台。 我们讨论了多少类/方法。采用指向 C++ 类的不透明指针并调用 C++ 方法的 C 填充程序并不困难,尽管我承认它可能会变得乏味。 对于初始项目 - 类不多。然而,将其视为一个更大项目的实践。该项目最终将涉及大量后端类移入核心 C++ 库。我认为那时我们需要自动生成代码。我同意编写 C 垫片很容易。只是最终手动维护的会太多。 跨平台和交叉编译器是不同的东西。在你的问题中具体。我可能是“跨平台的”,如果我对给定平台上的所有库/可执行文件使用相同的编译器,那么你的问题没有实际意义。 @Josh Petitt:核心逻辑最终应该在任何操作系统、任何 C++11 编译器上运行。用户界面代码可能更灵活——目前是 C++ 和 VCL。它可能特定于一个编译器/操作系统,或者可能更通用。稍后,它需要灵活地定位用户界面,如 Qt、.NET WPF(我认为 SWIG 可以提供帮助)、其他原生小部件工具包 - 谁知道 5 年后下一个流行的小部件工具包会是什么?我们希望做好准备。 【参考方案1】:如果它只需要在 Windows 上运行,我会将类公开为 COM 对象。它们仍将位于 DLL 中,并且可以被任何理解 COM 的语言使用。
【讨论】:
太棒了 - 现在你能推荐一个自动化工具来避免 COM 垃圾污染原始 C++ 库源代码吗?该库旨在跨平台,因此直接在库中的“原始”类上使用 ATL 之类的东西是行不通的。 (更不用说 COM 带来的 DLL 地狱)。 COM 不会“带来 dll 地狱”,如果您对某事有问题,至少只是说您不喜欢它,而不是编造无意义的借口。实际上,建议您今天将它们设为 WinRT 对象(它们是一种 COM 对象),因为您将无法很快摆脱它们。对于将为您的方法生成存根的自动化工具 - midl 或 DCE-RPC idl 生成器(即跨平台)将执行此操作 - 您将获得几乎与普通函数调用一样高效的进程内 RPC 调用.【参考方案2】:在 Windows 中执行此操作的“标准”方式是使用 COM 对象。因此,这当然是一个不错的选择。在 Linux 系统中,模块交互模型(例如,可执行文件-DLL 交互)非常不同,C++ 存在 ABI。
如果您想手动执行此操作(创建您自己的类似 COM 的库),可能需要认真对待许多棘手的小问题。你需要一个跨模块的 RTTI 系统,你需要一个接口查询/定义协议,一些跨模块管理内存的机制,等等。除此之外,为了“自动化”它,你可能需要 MACRO 和模板元函数。
我强烈建议您考虑或至少看看的一个跨平台选项是使用 Boost.Python 和 Python 语言作为模块之间的“粘合剂”。 Boost.Python 库基本上完成了整个“类的自动导出/导入”,但它将您的 C++ 类和函数导出为 Python 类和函数。而且,它是完全非侵入式和跨平台的,因此这确实是自动导出的理想示例。因此,您可能会考虑使用 Python 编写高级粘合代码,或者使用 Python 作为 C++ 模块之间的中间体,或者甚至重新设计 Boost.Python 库以仅使用“自动导出”机制来导出到任何接口您设计或使用的系统。
我敢肯定还有很多其他类似的库。但第一个问题当然是,你真的需要这个吗?您可能正在使用火箭筒杀死苍蝇。
【讨论】:
我将不得不进一步研究。我们有现有的“遗留”用户界面代码,我们希望与提议的更现代的 C++ 后端进行交互。由于 Boost.Python 说它可以用于调用 Python 或将类导出到 Python,因此它似乎可以工作。但是在混合中涉及另一种语言(如 Python)听起来非常笨拙。【参考方案3】:为什么不直接用 C++ builder 编译这个库呢?
【讨论】:
如果我们想编写一个现代 C++ 后端,我们正在寻找类似 (1) lambda 函数,(2) 与 TBB 和 OpenCV 等库的兼容性,(3) 良好的优化性能编译器(英特尔的编译器和 Visual C++ 都围绕 C++ Builder 运行)。这些是 C++ Builder 不支持的东西,老实说,我认为他们永远不会在这些方面赶上竞争对手。仅仅为了保持与此编译器的兼容性而保留我们新后端代码的质量似乎是一个糟糕的选择。 @JamesJohnston 听起来你的“问题”是你的前端,而不是你的后端。为您的漂亮后端制作接口所需的复杂性是否比仅仅在其上放置一个闪亮的新 GUI 的工作更多? (然后你可以从前到后使用你最喜欢的工具链)。 是的,前端是问题所在,该项目在用户界面中混入了太多核心逻辑。我希望看到的是将代码慢慢移入新的后端库 DLL 并修改用户界面以调用 DLL。最终,用户界面可以在以后重写,并且可以在任何地方使用相同的工具链。理想情况下,所有内容都可以一次重写,但由于时间/资源限制,这可能是不现实的——我认为它不会受到关注。最终,该设计还可以针对 Windows 以外的其他操作系统【参考方案4】:环顾 swig(我知道 swig 应该能够将 C++ 包装在 C 中): SWIG and C++
【讨论】:
【参考方案5】:如果核心库是跨平台的,为什么不将 UI 编写为跨平台 Qt 应用程序并在 Windows 上使用 Visual C++ 构建所有内容。
【讨论】:
最终是的,这就是我们的想法。不过就目前而言,在我们考虑重写 UI 之前,它必须是一个更加渐进的过渡。以上是关于混合来自不同编译器的 C++ 代码的主要内容,如果未能解决你的问题,请参考以下文章
使用不同的C++支持库的模块混合开发时,引发异常展开不正常,抛异常竟引出一个SIGSEGV
预编译头文件来自编译器的早期版本,或者预编译头为 C++ 而在 C 中使用它(或相反)
预编译头文件来自编译器的早期版本,或者预编译头为 C++ 而在 C 中使用它(或相反)