【问题标题】:Enforce linking with a shared library with -Wl,--as-needed (when only templates are provided)使用 -Wl,--as-needed 强制与共享库链接(仅提供模板时)
【发布时间】:2012-08-11 19:28:05
【问题描述】:

我正在创建一个仅模板的 C++ 库。但是,我还想提供一个“空”共享库,以便通过控制 SONAME,只要模板发生变化导致实例化模板 ABI 不兼容,我就可以强制重建模板消费者。

遗憾的是,如果特定用户的LDFLAGS 中有-Wl,--as-needed,则链接器将从NEEDED 中删除我的共享库,因为编译的可执行文件不向其中请求任何符号。如何确保程序始终与我的库链接,最好不要引入不必要的虚拟函数调用(或者如果我必须这样做,使它们的负担最小化)?

编辑:需要注意的是,特定的模板类提供了静态方法,通常只使用那些静态方法。因此,依赖于构造函数中的任何内容都不是一个好主意,我真的很想避免通过某种强制执行来加重所有方法的负担。


@EmployedRussian 的启发,我实现了:

extern int dummy;

namespace
{
    struct G
    {
        inline G()
        {
            dummy = 0;
        }
    };

    static const G g;
}

但遗憾的是,它为每个单元(包括头文件)执行一次分配。

【问题讨论】:

  • 不能-u linker option 帮忙吗?不需要从源进行虚拟调用。在-u 之后传递的符号将被视为未定义,并将链接所需的库
  • 刚刚试过了,好像不行。我想我应该添加-Wl,-u,some_symbol_in_the_library,对吗?
  • 嗯,我认为这只是 -u some_symbol_in_the_library 没有 -Wl 选项。让我检查一次
  • 很抱歉,但由于某种原因,我无法让它与示例程序一起使用!尽管即使在手册页中也提到了-u symbol 应该强制链接,但我清楚地记得至少在我使用过它的一种情况下。希望有人能指出正确的方向
  • 好吧,也许描述是在添加--as-needed之前。

标签: c++ templates shared-libraries


【解决方案1】:

但是,我还想提供一个“空”共享库,以便通过控制 SONAME,只要模板发生变化导致实例化模板 ABI 不兼容,我就可以强制重建模板使用者。

这将在运行时强制出错。

您可以在不使用SONAME 的情况下轻松获得相同的结果(运行时错误)。在您的模板标题之一中,放入一个将在运行时的全局对象

  1. 获取地址或致电libmysolib_version_<N>,或
  2. 执行dlopen(libmysolib.so, ...)dlsym("libmysolib_version_<N>", ...)

然后在每次破坏 ABI 时继续增加 N

最好不要引入不必要的虚拟函数调用

libmysolib_version_<N>的地址不调用函数;它只是强制运行时链接器找到该符号一次(在启动时)。您可能会与链接器垃圾收集发生冲突。

【讨论】:

  • 我得再考虑一下,但感谢您的提示,它确实帮助我将其归结为两种可能的解决方案。
  • 我只是在想……编译器会不会优化对象,因为得到的指针没有在任何地方使用?
  • 好的,我刚刚做了更多的测试,并且足够高的优化clang只是优化了整个块。
【解决方案2】:

我会推荐一种替代方法:

myheader.h 

namespace mylib_1 {
   void foo(); 
   //all the code goes there
}
namespace mylib = mylib_1;

用户调用:

mylib::foo()

使用不同 myheader 版本的代码不会链接,因为它会改变函数的签名。

ICU采用这种方法

【讨论】:

  • 这确实是一种有趣的方法……但是内联函数呢?
  • 嗯,这不是我想要的完全。这是一种很好的重命名形式,没错,它应该很好地解决潜在的 ABI 冲突。尽管如此,除非我遗漏了什么,否则它不允许使用模板强制重建所有包(即,如果实现是错误的)。
  • 如果您的库只是标题...所有函数都内联。关于强制重建。什么会迫使用户进行重建?他可以安装相同 SO 的旧版本和新版本,因为它们有不同的 soname。
  • 我的意思是它是一种非常好的技术,尤其是它可以防止一部分代码编译成不同版本的情况,所以如果你重建一部分,程序将无法链接而不重建所有代码(当然假设不同部分在它们之间的接口中使用您的库)
  • 我同意保持运行而不损坏是件好事。但是我们有解决方案可以在 SONAME 更改时(在包管理器中)重建包。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-06
  • 2016-01-02
  • 1970-01-01
  • 1970-01-01
  • 2011-05-24
  • 1970-01-01
相关资源
最近更新 更多