【问题标题】:How to support dynamic plugins when statically linking in standard libraries?在标准库中静态链接时如何支持动态插件?
【发布时间】:2017-12-16 01:41:31
【问题描述】:

假设应用程序myapp.exe 是使用g++ 构建的,并且它使用标志-static-libstdc++,因此它可以安装在没有libstdc++.so 的环境中。 myapp.exe 还添加了对某些函数 plugf 的插件支持,这些函数可以通过 dlopen 从分片库中动态加载。

如果libplug.so 是这样一个插件库,它也链接到libstdc++,它如何以能够与myapp.exe 一起工作的方式这样做?

如果libstdc++ 是动态链接的,这很简单,因为myapp.exelibplug.so 都可以使用相同的动态加载的标准库,但我不清楚如何最好地使用静态链接的标准库来做到这一点。

我正在考虑的一种方法是让libplug.so 也使用标志-static-libstdc++,然后使用version script

{
  global: plugf;
  local: *;
};

以确保使用它的标准库版本,但这意味着将有两个libstdc++ 的副本加载到内存中。我知道这种方法不会受到 C++ 标准的祝福,因为它会违反 ORD,但是libstdc++ 以任何方式支持它吗?其manual 部分的Multiple ABI testing 部分确实引用了一个听起来相似的场景。

【问题讨论】:

  • 遗憾的是,您将需要分发一个动态/静态链接的 libstdc++ 以匹配 libplug.so - 是的,将在运行时加载两个副本。是的,如果你的插件返回一个带有一个版本的 libstdc++ 的指针,而你用另一个版本释放它,你可能会遇到麻烦。
  • 我认为这不是真的。分配由标准 c 库处理,-static-libstdc++ 不会导致libc 静态链接,因此它们都使用相同的libc.so
  • 我认为在 libstdc++ 中对象是用__gnu_cxx::new_allocator 分配的,也许正如您指出的那样,它们都指向同一个libc.so。根据个人经验,我在使用 MSVC 的 RT 时遇到了上述问题。
  • 诸如new int{123} 之类的标准分配调用operator new,在libstdc++ 中它只是malloc 的一个包装器。 (见here)。
  • 是的,取决于你如何构建它,例如你可能混合了不同版本的 libc。这就是为什么 HDL 之类的库不公开内存分配的原因。无论如何,支持动态插件的系统依赖于动态库确实避免了重复。这就是发明 dll 的原因。减轻部署策略影响的一种方法是严重依赖 LTO。

标签: c++ gcc ld libstdc++


【解决方案1】:

是的,这个解决方案可以,但是

  • 由于代码重复,它会引入一定的开销
  • 由于ABI changes in recent libstdc++,如果您尝试在插件/应用程序之间传递 STL 对象,它可能会中断

删除由std::allocator 在不同的 C++ 运行时分配的对象应该可以在 Linux 上工作,尽管我在 libstdc++ 文档中找不到关于此的明确声明。正如 Mikhail 在 cmets 中指出的那样,它在 Windows 上确实失败了。

【讨论】:

  • 不过,ABI 更改仅在 C++98 和 C++11 版本的 libstdc++ 之间进行,对吧?
  • @rnickb 不,无论-std 标志如何,您都将在所有 GCC5 后的 libstdc++ 中获得新的 ABI(有关更多详细信息,请参阅this page)。这有点道理,因为用-std=c++98-std=c++11 编译的代码中的std::string 应该更好地兼容二进制。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-19
  • 1970-01-01
  • 1970-01-01
  • 2015-02-25
  • 2019-08-13
  • 1970-01-01
  • 2011-03-16
相关资源
最近更新 更多