跨编译器二进制兼容 c++ 接口


#1

C++ 没有标准 ABI, C 标准也没有。但是每个平台都有定义自己平台的标准 C ABI。因此 C 接口就是这个平台的标准接口。 然而没有哪个平台还有闲功夫去定义 C++ 的标准 ABI , 于是就丢给 C++ 编译器“自主” 选择了。

这个自主选择的结果就是,不同编译器的 C++ 库不能混用。除非 C++ 库实际上是导出的 C 接口。

这样就失去了 C++ 在接口上的通用灵活的优势。

然而, Boost 的出现给哇们带来了一丝曙光。

这个 Boost 带给我们的答案是: Header Only.

咋一看,似乎早就知道了,没啥值得大书特书的。且慢 !!

我说的是 Header Only 加 C style exported function !

这是什么意思呢?

动态库,其基础还是一样,导出为 C 接口。比如 myobj->foo() 这样的接口导出为 obj_foo(myobj); 然后函数参数上还是只使用基本 C 类型和 POD 类型。

但是! 提供一个 Header Only 的封装库!

于是

库里的 C++ 代码:

#include "exported_function.h" // 这里是 C 导出函数的定义, struct myclass_t 前向声明而已。
#include "myclass.hpp" // 这里有 myclass_t 的定义

extern "C" void my_class_foo(myclass_t * self, const char* param1)
{
    self->foo(std::string(param1)); 
}

库的 公开头文件

//  。。。 神码 declspec(dllimport) 之类的 。。。
extern "C" myclass_t * my_class_new(...);
extern "C" void my_class_delete(myclass_t * self);
extern "C" void my_class_foo(myclass_t * self, const char* param1);

库的公开头文件,Header only wrap


class myclass{
public:
   myclass(){
    m_impl.reset(my_class_new ...,  my_class_delete);
  }
   void foo(std::string param1){
     my_class_foo(m_impl.get(), param1.c_str());     
   }

   std::unique_ptr<my_class_t, decltype(my_class_delete)> m_impl;
};

这样,库的真正对外接口还是 C++ 的,用起来方便,还有 RAII 帮助。然后库在跨 DLL 层面上还是通过 C 接口完成的。无需考虑c++编译器的ABI兼容性。