针对GNU ++ 98 / libstdc ++编译的应用程序是否可以链接到针对C ++ 11 / libc ++构建的dylib?

时间:2016-10-25 20:32:36

标签: c++ xcode c++11 linker dylib

我有一个使用Xcode 7.2.1构建的C ++应用程序,使用GNU ++ 98方言编译并链接到libstdc ++。我需要调用一个用C ++ 11编译并与libc ++链接的dylib。

使用dylib类成员中的默认属性可见性:

extern __attribute__((visibility("default"))) void foo(std::string const&, int);

...显示没有ABI兼容性(至少对于字符串) - 任何具有std :: string参数的dylib函数都无法链接到应用程序。

是一个适当的解决方案来创建一个重载的C ++成员函数,它只将在dylib端构造的char * params传递给std :: string,还是有其他需要为dylib创建纯C API的陷阱?

注意:现在已经阅读了关于ABI兼容性问题的This excellent explanation,看来似乎没什么希望,但是为std :: string params构建了一个基于char的API ...

1 个答案:

答案 0 :(得分:1)

使用标准布局类编写API。

标准布局类可能很花哨。

这是我脑海中未编译的array_view

template<class Container>
using data_ptr_type = decltype( std::declval<Container>().data() );

template<bool b>
using bool_kt = std::integral_constant<bool, b>;

template<class T>
struct array_view {
  T* b = nullptr;
  T* e = nullptr;
  T* begin() const { return b; }
  T* end() const { return b; }
  template<class U>
  using ptr_is_compatible = bool_kt<
    std::is_same< U, T* >{} || std::is_same< U, std::remove_const_t<T>* >{} ||
    std::is_same< U, std::remove_volatile_t<T>* >{} || std::is_same< U, std::remove_cv_t<T>* >{}
  >;

  // convert from .data() and .size() containers:
  template<class In,
    std::enable_if_t<
      ptr_is_compatible< data_ptr_type< In& > >{}, int
    > = 0
  >
  array_view( In&& in ):array_view(in.data(), in.size()) {}

  // special ones:
  array_view()=default;
  array_view(array_view const&)=default;
  array_view& operator=(array_view const&)=default;

  // manual ones:
  array_view( T* ptr, std::size_t N ):array_view(ptr, ptr+N) {}
  array_view( T* s, T* f ):b(s), e(f) {}

  // from C-style array:
  template<class U, std::size_t N,
    std::enable_if_t<
      ptr_is_compatible< U* >{}
    ,int> = 0
  >
  array_view( U(&arr)[N] ):array_view(arr, N) {}

  template<class Container>
  Container copy_to() const {
    return {begin(), end()};
  }
};

虽然很花哨,但它是标准布局。因此,只有最疯狂的ABI变化才能打破它。

现在你的头文件是:

extern __attribute__((visibility("default"))) void foo(array_view<const char>, int);

并且来电者可以使用foo( "hello", 7 )foo( std::string("hello"), 42 )foo( std::vector<char>{'a', 'b', 'c'}, 18 )或其他任何方式调用它。你不在乎。

指向缓冲区开头的指针是在来电方面完成的,所以你不知道所传递内容的布局。

在内部,如果需要,您可以使用arg.to<std::string>()封送回容器。