我有一个不起作用的设置,我不知道我在这里做错了什么 - 我正在尝试将项目从手工制作的Makefile转换为autotools,我认为我已经将其大部分设置正确,因为应用程序及其所有便利库构建和链接正确,但是全局状态初始化器存在一些问题。便利图书馆。
有些库在代码中遵循这样的模式:
// in global scope of somemodule.cpp
namespace {
bool registered = ModuleShare::registerModule<SomeModule>("SomeModule");
}
此代码与实际模块源一起使用libtool
编译到便捷库中// libsomething Makefile.am
noinst_LTLIBRARIES = libsomething.la
libsomething_la_SOURCES = \
[ ... ]
moduleshare.cpp moduleshare.h \
somemodule.cpp somemodule.h \
[ ... ]
并且构建了这个库,并在应用程序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
我修改了ModuleShare :: registerModule以验证它未被调用:
template<typename T>
static bool registerModule(const std::string &module){
printf("%s\n", module.c_str());
[ ... ]
return true;
}
这可能是什么原因?
修改
此时,我已经发现这个问题与允许在链接期间删除未使用的符号的链接器有关。如果我使用--whole-archive
手动链接,一切都按预期工作。
来自C背景,我也试过
static void
__attribute__((constructor))
register (void)
{
ModuleShare::registerModule<SomeModule>("SomeModule");
}
但这也不会产生我所期望的行为,这很奇怪,因为我在私人C项目中依赖这个构造。
此时,我愿意向任何方向提出建议。我知道libtool不提供LDADD中的每个库标志,我不能,并且根本不想用--whole-archive编译所有内容只是为了摆脱这些症状。我对代码库的控制有限,但我认为我真正需要问的是,使用autotools在便捷库中初始化程序状态的好方法是什么?
EDIT2:
我认为我更近了一步 - 似乎应用程序代码没有调用便捷库,因此链接器省略了它。应用程序仅通过SomeModule
头文件中定义的模板化函数调用库,该文件依赖于在便捷库中调用的静态初始化器。
这种依赖性回归正在搞砸整个构建。
不过,我不确定如何解决这个问题:/
谢谢, 安迪
答案 0 :(得分:5)
由于您使用的是自动工具,因此您可能处于可以独占使用gcc的情况。在这种情况下,您可以应用`used'属性来告诉gcc强制链接器包含符号:
namespace {
__attribute__ ((used))
bool registered = ModuleShare::registerModule<SomeModule>("SomeModule");
}
答案 1 :(得分:5)
您是否尝试添加-u registered
而不是使用--whole-archive?
如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.
编辑:我认为您尝试实现的目标与Qt的插件管理非常相似。 This文章详细介绍了一下。 this是4.8的官方文档。
考虑到便利库是静态构建的,也许,在这个便利库中创建一个虚拟实例(或者registered
的虚拟用法)就足够了,并将其声明为extern
你使用它(这就是Q_EXPORT_PLUGIN2和Q_IMPORT_PLUGIN正在做的事情。)
答案 2 :(得分:4)
这个答案可能需要为您修改太多代码,但我会提到它。正如我之前提到的,便捷库模型是一种静态链接,其中在最终链接到封装库之前将库整理在一起。仅在这种情况下,“库”是可执行文件。所以我想象未命名的命名空间中的东西(本质上是static
变量),特别是未引用的变量将被删除。使用上面的代码,它可以像我预期的那样工作。
我能够得到registerModule
来打印它的消息,而没有像这样的便利库中的特殊链接器技巧:
<强> somemodule.cpp 强>
// in global scope
namespace registration {
bool somemodule = ModuleShare::registerModule<SomeModule>("SomeModule");
}
<强> someapp.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
}