libtool连接 - 便利图书馆的全球状态初始化

And*_*tin 6 c++ autotools libtool

我有一个不起作用的设置,我不知道我在这里做错了什么 - 我正在尝试将项目从手工制作的Makefile转换为autotools,我认为我的大部分设置正确,因为应用程序和它的所有便利库都可以正确构建和链接,但是便利库的全局状态初始化器存在一些问题.

一些库在代码中遵循这样的模式:

// in global scope of somemodule.cpp
namespace {
  bool registered  = ModuleShare::registerModule<SomeModule>("SomeModule");
}
Run Code Online (Sandbox Code Playgroud)

此代码与实际模块源一起使用libtool编译到便捷库中

// libsomething Makefile.am
noinst_LTLIBRARIES = libsomething.la

libsomething_la_SOURCES = \
  [ ... ]
  moduleshare.cpp moduleshare.h \
  somemodule.cpp somemodule.h \
  [ ... ] 
Run Code Online (Sandbox Code Playgroud)

并且构建了这个库,并在应用程序Makefile.am中引用如下:

// someapp Makefile.am
bin_PROGRAMS = someapp

someapp_SOURCES = someapp.c someapp.h
someapp_CPPFLAGS = -I ${top_srcdir}/something
someapp_LDADD = ${top_srcdir}/something/libsomething.la
Run Code Online (Sandbox Code Playgroud)

我修改了ModuleShare :: registerModule来验证它没有被调用:

template<typename T>
static bool registerModule(const std::string &module){
  printf("%s\n", module.c_str());

  [ ... ]

  return true;
}
Run Code Online (Sandbox Code Playgroud)

这可能是什么原因?

编辑:

此时,我已经发现这个问题与链接器有关,链接器允许在链接期间删除未使用的符号.如果我手动链接使用--whole-archive,一切都按预期工作.

来自C背景,我也尝试过

static void
__attribute__((constructor))
register (void)
{
  ModuleShare::registerModule<SomeModule>("SomeModule");
}
Run Code Online (Sandbox Code Playgroud)

但考虑到我在私人C项目中依赖这个构造,这也不会产生我所期望的行为,这很奇怪.

在这一点上,我愿意接受任何方向的建议.我知道libtool不提供LDADD中的每个库标志,我不能,并且根本不想用--whole-archive编译所有内容只是为了摆脱这些症状.我对代码库的控制有限,但我认为我真正需要问的是,使用autotools在便利库中初始化程序状态的好方法是什么?

EDIT2:

我认为我更近了一步 - 似乎应用程序代码没有调用便捷库,因此链接器省略了它.应用程序仅通过在头文件中定义的模板化函数调用库,该函数SomeModule依赖于在便捷库中调用的静态初始化器.这种依赖性回归正在搞砸整个构建.

不过,我不确定如何解决这个问题:/

谢谢,安迪

cre*_*hen 5

由于您使用的是自动工具,因此您可能处于可以独占使用gcc的情况.在这种情况下,您可以应用`used'属性来告诉gcc强制链接器包含符号:

namespace {
    __attribute__ ((used))
    bool registered  = ModuleShare::registerModule<SomeModule>("SomeModule");
}
Run Code Online (Sandbox Code Playgroud)


jcm*_*jcm 5

而不是使用--whole-archive,你试图只添加-u registered

作为ld手册说明:

-u symbol
   --undefined=symbol
       Force symbol to be entered in the output file as an undefined symbol.  Doing this may, for example, trigger linking of additional modules from standard libraries.  -u may be repeated with different option arguments to
       enter additional undefined symbols.  This option is equivalent to the "EXTERN" linker script command.
Run Code Online (Sandbox Code Playgroud)

编辑:我认为你试图实现的与Qt的插件管理非常相似.文章详细介绍了它一下.而是4.8的官方文档.

考虑到便捷库是静态构建的,也许,在这个便利库中创建一个虚拟实例(或者虚拟使用registered)就足够了,并将它声明为extern你使用它的地方(这就是Q_EXPORT_PLUGIN2和Q_IMPORT_PLUGIN正在做的事情) .


lda*_*v1s 4

这个答案可能需要您进行太多代码更改,但我会提到它。正如我之前提到的,便利库模型是一种静态链接,其中在最终链接到封装库之前将库整理在一起。只有在这种情况下,“库”才是可执行文件。所以我想象未命名的命名空间中的东西(static本质上是变量),特别是未引用的变量将被删除。通过上面的代码,它按照我的预期工作了。

我能够registerModule在这样的便利库中打印它的消息,而无需特殊的链接器技巧:

一些模块.cpp

// in global scope
namespace registration {
  bool somemodule  = ModuleShare::registerModule<SomeModule>("SomeModule");
}
Run Code Online (Sandbox Code Playgroud)

一些应用程序.cpp

// somewhere
namespace registration {
    extern bool somemodule;
    ... // and all the other registration bools
}

// in some code that does initialization, possibly
if (!(registration::somemodule && ...)) {
    // consequences of initialization failure
}
Run Code Online (Sandbox Code Playgroud)